diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..5cbe254 --- /dev/null +++ b/.clang-format @@ -0,0 +1,14 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +ColumnLimit: 100 +BraceWrapping: + AfterFunction: false + AfterControlStatement: false + AfterClass: false + AfterEnum: false + AfterStruct: false + AfterNamespace: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false diff --git a/ToDo.txt b/ToDo.txt deleted file mode 100644 index ac29ba7..0000000 --- a/ToDo.txt +++ /dev/null @@ -1,10 +0,0 @@ - -1) OTA switch to Minio - -2) Global variable ( Circular or Linear LEDS) - -3) Long Hold to switch - -4) Fix white flasing at booth - -5) \ No newline at end of file diff --git a/data/booths/roamer-big.json b/data/booths/big-roam.json similarity index 93% rename from data/booths/roamer-big.json rename to data/booths/big-roam.json index 1a15f18..4041ad6 100644 --- a/data/booths/roamer-big.json +++ b/data/booths/big-roam.json @@ -1,5 +1,7 @@ { + "profile": "big-roam", "mode": "roamer", + "limited-mode": false, "button": 0, "buttons": [ @@ -58,7 +60,7 @@ "en": true, "relay-index": 0, "button-index": 0, - "min": 0.0, + "min": 1.0, "max": 100.0, "step": 1.5, "rate": 30.0, @@ -66,10 +68,10 @@ "vision": true }, { - "en": false, + "en": true, "relay-index": 1, "button-index": 1, - "min": 0.0, + "min": 1.0, "max": 100.0, "step": 1.5, "rate": 30.0, @@ -106,9 +108,9 @@ "size": 168, "chip": "SK6812", "rgb-order": "rgb", - "shift":-5, + "shift":-42, "offset": 0, - "bright": 200, + "bright": 240, "power-div": 0, "i2s-ch": 0, "core": 1 diff --git a/data/booths/custom.json b/data/booths/custom.json index 9f7eb89..582a898 100644 --- a/data/booths/custom.json +++ b/data/booths/custom.json @@ -1,5 +1,7 @@ { + "id": "custom", "mode": 0, + "limited-mode": false, "buttons": [ { @@ -54,14 +56,26 @@ "ramp-lights": [ { - "en": true, - "relay-index": 0, - "button-index": 0 + "en": true, + "relay-index": 0, + "button-index": 0, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true }, { - "en": true, - "relay-index": 1, - "button-index": 1 + "en": true, + "relay-index": 1, + "button-index": 1, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true } ], "oled": { diff --git a/data/booths/helio-flare.json b/data/booths/flare-posh.json similarity index 80% rename from data/booths/helio-flare.json rename to data/booths/flare-posh.json index 50419d5..30e35bf 100644 --- a/data/booths/helio-flare.json +++ b/data/booths/flare-posh.json @@ -1,6 +1,8 @@ { - "mode": 0, - "buttons": + "id": "flare-posh", + "mode": 0, + "limited-mode": false, + "buttons": [ { "en": true @@ -56,12 +58,24 @@ { "en": true, "relay-index": 0, - "button-index": 0 + "button-index": 0, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true }, { - "en": false, + "en": true, "relay-index": 1, - "button-index": 1 + "button-index": 1, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true } ], "oled": { diff --git a/data/booths/helio-posh.json b/data/booths/helio-posh.json deleted file mode 100644 index d43fabd..0000000 --- a/data/booths/helio-posh.json +++ /dev/null @@ -1,124 +0,0 @@ -{ - "buttons": - [ - { - "en": true - }, - { - "en": true - }, - { - "en": true - } - ], -"pwmout": - [ - { - "en": true, - "freq": 250, - "min": 0, - "max": 100, - "default": 0, - "vision": false, - "deltarate": 0 - }, - { - "en": true, - "freq": 250, - "min": 0, - "max": 100, - "default": 0, - "vision": false, - "deltarate": 0 - }, - { - "en": true, - "freq": 250, - "min": 0, - "max": 100, - "default": 0, - "vision": true, - "deltarate": 0 - }, - { - "en": true, - "freq": 250, - "min": 0, - "max": 100, - "default": 0, - "vision": true, - "deltarate": 0 - } - ], - "ramp-lights": - [ - { - "en": true, - "relay-index": 0, - "button-index": 0 - }, - { - "en": false, - "relay-index": 1, - "button-index": 1 - } - ], - "oled": { - "en": false, - "height": 64, - "width": 128 - }, - "t-sensor": { - "en": true, - "addr": 72, - "sp1": 85.0, - "fan-pwr1": 50.0, - "sp2": 90.0, - "fan-pwr2": 100.0, - "hyst": 1.0, - "relay": 3, - "interval": 5000 - }, - "adc": { - "ain1_factor": 1.0 - }, - "status-led":{ - "interval": 250 - }, - "strips": - [ - { - "en": true, - "size": 138, - "chip": "SK6812", - "rgb-order": "rgb", - "shift":-27, - "offset": 0, - "power-div": 0, - "i2s-ch": 0, - "core": 1 - }, - { - "en": true, - "size": 30, - "chip": "SK6812", - "rgb-order": "rgb", - "shift":-27, - "offset": 0, - "power-div": 0, - "i2s-ch": 0, - "core": 1 - } - ], - "rx433": { - "en": "true" - }, - "tx433": { - "en": "true" - }, - "ble":{ - "en": true, - "name": "Ata_Lights", - "core": 1 - } -} diff --git a/data/booths/lumia-m.json b/data/booths/m-lumia.json similarity index 83% rename from data/booths/lumia-m.json rename to data/booths/m-lumia.json index d576c73..ff73390 100644 --- a/data/booths/lumia-m.json +++ b/data/booths/m-lumia.json @@ -1,4 +1,6 @@ { + "id": "m-lumia", + "limited-mode": false, "mode": 0, "buttons": [ @@ -56,12 +58,24 @@ { "en": true, "relay-index": 0, - "button-index": 0 + "button-index": 0, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true }, { "en": true, "relay-index": 1, - "button-index": 1 + "button-index": 1, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true } ], "oled": { diff --git a/data/booths/m1.json b/data/booths/m1.json index b4fae80..5e8798d 100644 --- a/data/booths/m1.json +++ b/data/booths/m1.json @@ -1,4 +1,5 @@ { + "id": "m1", "mode": 0, "buttons": [ @@ -56,12 +57,24 @@ { "en": true, "relay-index": 0, - "button-index": 0 + "button-index": 0, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true }, { "en": true, "relay-index": 1, - "button-index": 1 + "button-index": 1, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true } ], "oled": { diff --git a/data/booths/marquee.json b/data/booths/marquee.json index b4fae80..dae0d81 100644 --- a/data/booths/marquee.json +++ b/data/booths/marquee.json @@ -1,5 +1,7 @@ { + "id": "marquee", "mode": 0, + "limited-mode": false, "buttons": [ { @@ -56,12 +58,24 @@ { "en": true, "relay-index": 0, - "button-index": 0 + "button-index": 0, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true }, { "en": true, "relay-index": 1, - "button-index": 1 + "button-index": 1, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true } ], "oled": { diff --git a/data/booths/roamer.json b/data/booths/orig-roam.json similarity index 93% rename from data/booths/roamer.json rename to data/booths/orig-roam.json index 64faa59..f79dab6 100644 --- a/data/booths/roamer.json +++ b/data/booths/orig-roam.json @@ -1,5 +1,7 @@ { + "id": "orig-roam", "mode": "roamer", + "limited-mode": false, "button": 0, "buttons": [ @@ -58,19 +60,21 @@ "en": true, "relay-index": 0, "button-index": 0, - "min": 0.0, + "min": 1.0, "max": 100.0, "step": 1.5, + "rate": 30.0, "skip-count": 5, "vision": true }, { - "en": false, + "en": true, "relay-index": 1, "button-index": 1, - "min": 0.0, + "min": 1.0, "max": 100.0, "step": 1.5, + "rate": 30.0, "skip-count": 5, "vision": true } diff --git a/data/booths/helio-sport.json b/data/booths/spectra.json similarity index 82% rename from data/booths/helio-sport.json rename to data/booths/spectra.json index d04844e..b0f38cb 100644 --- a/data/booths/helio-sport.json +++ b/data/booths/spectra.json @@ -1,5 +1,7 @@ { + "id": "spectra", "mode": 0, + "limited-mode": false, "buttons": [ { @@ -56,12 +58,24 @@ { "en": true, "relay-index": 0, - "button-index": 0 + "button-index": 0, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true }, { - "en": false, + "en": true, "relay-index": 1, - "button-index": 1 + "button-index": 1, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true } ], "oled": { diff --git a/data/booths/lumia-spectra.json b/data/booths/sport.json similarity index 83% rename from data/booths/lumia-spectra.json rename to data/booths/sport.json index b4fae80..f4408ad 100644 --- a/data/booths/lumia-spectra.json +++ b/data/booths/sport.json @@ -1,5 +1,7 @@ { + "id": "sport", "mode": 0, + "limited-mode": false, "buttons": [ { @@ -56,12 +58,24 @@ { "en": true, "relay-index": 0, - "button-index": 0 + "button-index": 0, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true }, { "en": true, "relay-index": 1, - "button-index": 1 + "button-index": 1, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true } ], "oled": { diff --git a/data/booths/light-stik.json b/data/booths/stik.json similarity index 86% rename from data/booths/light-stik.json rename to data/booths/stik.json index 21c6e2e..5e3390c 100644 --- a/data/booths/light-stik.json +++ b/data/booths/stik.json @@ -1,4 +1,5 @@ { + "profile": "stik", "mode": "stik", "buttons": [ @@ -56,13 +57,25 @@ { "en": true, "relay-index": 0, - "button-index": 0 + "button-index": 0, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true }, { "en": true, "relay-index": 1, - "button-index": 1 - } + "button-index": 1, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true + } ], "oled": { "en": false, diff --git a/data/booths/testbooth.json b/data/booths/testbooth.json index 9f33075..21a19df 100644 --- a/data/booths/testbooth.json +++ b/data/booths/testbooth.json @@ -1,4 +1,5 @@ { + "profile": "testbooth", "mode": 0, "buttons": [ @@ -54,24 +55,26 @@ "ramp-lights": [ { - "en": false, - "relay-index": 0, - "button-index": 0, - "min": 5.0, - "max": 100.0, - "step": 1.5, - "skip-count": 5, - "vision": true + "en": true, + "relay-index": 0, + "button-index": 0, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true }, { - "en": false, - "relay-index": 1, - "button-index": 1, - "min": 5.0, - "max": 100.0, - "step": 1.5, - "skip-count": 5, - "vision": true + "en": true, + "relay-index": 1, + "button-index": 1, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true } ], "oled": { diff --git a/data/booths/lumia-xl.json b/data/booths/xl-lumia.json similarity index 85% rename from data/booths/lumia-xl.json rename to data/booths/xl-lumia.json index 76d799f..88ae171 100644 --- a/data/booths/lumia-xl.json +++ b/data/booths/xl-lumia.json @@ -1,5 +1,7 @@ { + "id": "xl-lumia", "mode": 0, + "limited-mode": false, "buttons": [ { @@ -56,12 +58,24 @@ { "en": true, "relay-index": 0, - "button-index": 0 + "button-index": 0, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true }, { - "en": true, + "en": false, "relay-index": 1, - "button-index": 1 + "button-index": 1, + "min": 1.0, + "max": 100.0, + "step": 1.5, + "rate": 30.0, + "skip-count": 5, + "vision": true } ], "oled": { diff --git a/data/system/ble.json b/data/system/ble.json index 82da5c8..c43135f 100644 --- a/data/system/ble.json +++ b/data/system/ble.json @@ -1,5 +1,5 @@ { - "name": "ATALIGHTS", + "name": "SP110E-ATA", "unique": true, "lights-service": "FFE0", "lights-char": "FFE1", diff --git a/data/system/system.json b/data/system/system.json index 83bdb32..c01e52c 100644 --- a/data/system/system.json +++ b/data/system/system.json @@ -1,4 +1,4 @@ { "boardfile": "/boards/board15.json", - "configfile": "/booths/roamer-big.json" + "configfile": "/booths/big-roam.json" } \ No newline at end of file diff --git a/data/www/ata-boothifier-upgrade.html b/data/www/ata-boothifier-upgrade.html index 53868db..64c5009 100644 --- a/data/www/ata-boothifier-upgrade.html +++ b/data/www/ata-boothifier-upgrade.html @@ -589,67 +589,67 @@ IMPORTANT NOTES: try{ bleDevice = await navigator.bluetooth.requestDevice({ - filters:[{ namePrefix: el.inDeviceName.value || BLE_SERVER_NAME }], - optionalServices:[BLE_SERVICE_UUID] - }); + filters:[{ namePrefix: el.inDeviceName.value || BLE_SERVER_NAME }], + optionalServices:[BLE_SERVICE_UUID] + }); - const server = await bleDevice.gatt.connect(); - const service = await server.getPrimaryService(BLE_SERVICE_UUID); - bleCharacteristic1 = await service.getCharacteristic(BLE_CHARACTERISTIC1_UUID); - bleCharacteristic2 = await service.getCharacteristic(BLE_CHARACTERISTIC2_UUID); - await bleCharacteristic2.startNotifications(); - let prevProgressFound = false; - bleCharacteristic2.addEventListener('characteristicvaluechanged', e => { - try{ - //const view = e.target.value; // DataView - //const bytes = new Uint8Array(view.buffer, view.byteOffset, view.byteLength); - - // Debug info - //let debugInfo = `Received ${bytes.length} bytes: `; - //for (let i = 0; i < bytes.length; i++) { - // debugInfo += bytes[i].toString(16).padStart(2, '0') + ' '; - // } - //console.log(debugInfo); - - // Try to decode as text - let txt = ''; - try { - //txt = new TextDecoder().decode(bytes); - txt = new TextDecoder().decode(e.target.value); - // Remove null terminators and trim - const nullIdx = txt.indexOf('\0'); - if (nullIdx !== -1) txt = txt.slice(0, nullIdx); - txt = txt.trim(); - } catch (decodeErr) { - console.error('Text decode error:', decodeErr); - // Fallback to showing hex if text decode fails - txt = '[Binary data]'; - } - - // Show both raw and processed data in console - //console.log('--> Raw bytes:', bytes); - //console.log('--> As text:', txt); - - //logMessage(`--> (${bytes.length} bytes) ${txt}`); - // progress messages handling variable captured from outer scope + const server = await bleDevice.gatt.connect(); + const service = await server.getPrimaryService(BLE_SERVICE_UUID); + bleCharacteristic1 = await service.getCharacteristic(BLE_CHARACTERISTIC1_UUID); + bleCharacteristic2 = await service.getCharacteristic(BLE_CHARACTERISTIC2_UUID); + await bleCharacteristic2.startNotifications(); + let prevProgressFound = false; + bleCharacteristic2.addEventListener('characteristicvaluechanged', e => { + try{ + //const view = e.target.value; // DataView + //const bytes = new Uint8Array(view.buffer, view.byteOffset, view.byteLength); + + // Debug info + //let debugInfo = `Received ${bytes.length} bytes: `; + //for (let i = 0; i < bytes.length; i++) { + // debugInfo += bytes[i].toString(16).padStart(2, '0') + ' '; + // } + //console.log(debugInfo); + + // Try to decode as text + let txt = ''; + try { + //txt = new TextDecoder().decode(bytes); + txt = new TextDecoder().decode(e.target.value); + // Remove null terminators and trim + const nullIdx = txt.indexOf('\0'); + if (nullIdx !== -1) txt = txt.slice(0, nullIdx); + txt = txt.trim(); + } catch (decodeErr) { + console.error('Text decode error:', decodeErr); + // Fallback to showing hex if text decode fails + txt = '[Binary data]'; + } + + // Show both raw and processed data in console + //console.log('--> Raw bytes:', bytes); + //console.log('--> As text:', txt); + + //logMessage(`--> (${bytes.length} bytes) ${txt}`); + // progress messages handling variable captured from outer scope - if(prevProgressFound && txt.includes('progress')){ - logMessage(`${txt}`, true); // overwrite last line for progress updates - } - else{ - logMessage(`${txt}`); - prevProgressFound = false; // reset if current message isn't progress - } + if(prevProgressFound && txt.includes('progress')){ + logMessage(`${txt}`, true); // overwrite last line for progress updates + } + else{ + logMessage(`${txt}`); + prevProgressFound = false; // reset if current message isn't progress + } - if(txt.includes('progress')){ - prevProgressFound = true; - } + if(txt.includes('progress')){ + prevProgressFound = true; + } - } catch(err) { - console.error('Processing error', err); - logMessage('--> Error processing message: ' + err.message); - } + } catch(err) { + console.error('Processing error', err); + logMessage('--> Error processing message: ' + err.message); + } }); bleConnected=true; diff --git a/data/www/usercfg.html b/data/www/usercfg.html new file mode 100644 index 0000000..39598df --- /dev/null +++ b/data/www/usercfg.html @@ -0,0 +1,1324 @@ + + + + + + + ATA Lights Config + + + + + +
+
+ 🌡️ Temp: --.- °F +
+

ATA Lights Config

+
+ ⚡ V-IN: --.- V +
+
+ +
+
+
+
BLE Comm: Disconnected
+
+ +
+ + + + + +
+ + + +
+ + +
+
+ Communication + +
+ + +
+ +
+
+
+
+ + +
+
+ +
+ Core Settings + +
+
Limited Mode
+
+ + +
+
+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
px
+
+ +
+ + +
+
+
+ + +
+ Fan / Temperature + +
+ + +
°C
+
+ +
+ + +
°C
+
+
+ + +
+ Front White Light Range + +
+ + +
%
+
+ +
+ + +
%
+
+
+ + +
+ Rear White Light Range + +
+ + +
%
+
+ +
+ + +
%
+
+
+
+ + +
+
+ +
+
+ + +
+
+ + + +
+ + +
+
+ Tools + +
+ + +
+ +
+
+ +
+ + +
+ +
+
+ +
+ + +
+ +
+
+ +
+ + +
+ +
+
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/docs/SP110E Info.xlsx b/docs/SP110E Info.xlsx new file mode 100644 index 0000000..c00563f Binary files /dev/null and b/docs/SP110E Info.xlsx differ diff --git a/docs/ToDo.txt b/docs/ToDo.txt new file mode 100644 index 0000000..50f6811 --- /dev/null +++ b/docs/ToDo.txt @@ -0,0 +1,24 @@ + +Board to do: +2) make sure no fixed indexes to pwmOutput and other peripherals + +3) Implement sending packet with current values to ble appearance + +4) figure out how to compare profile comparison before savoing to system.json + +5) made mode string instead of number. + +6) Comments on json file Enable? + #define ARDUINOJSON_ENABLE_COMMENTS 1 + #include + + permits: // or /* lsslslslslsl */ + + +7) Use same struct of setting for to and from in ble + +8) learn about Blob in BLE + +######### Configuration Page ############ +done + \ No newline at end of file diff --git a/docs/~$SP110E Info.xlsx b/docs/~$SP110E Info.xlsx new file mode 100644 index 0000000..8b381df Binary files /dev/null and b/docs/~$SP110E Info.xlsx differ diff --git a/esp32s3_atabooth_8mb.code-workspace b/esp32s3_atabooth_8mb.code-workspace index 2ce8fdd..c92c6d8 100644 --- a/esp32s3_atabooth_8mb.code-workspace +++ b/esp32s3_atabooth_8mb.code-workspace @@ -2,9 +2,6 @@ "folders": [ { "path": "." - }, - { - "path": "../esp32s3_module_8mb" } ], "settings": { diff --git a/include/ATALights.h b/include/ATALights.h index 4545449..ef1cc89 100644 --- a/include/ATALights.h +++ b/include/ATALights.h @@ -5,13 +5,21 @@ #include "ColorPalettes.h" #include "PWM_Output.h" -#define PIXEL_INDEX -3 +#define SHIFT_INDEX -3 #define SOLID_COLOR_INDEX -2 #define OFF_INDEX -1 #define WITH_GAPS true #define NO_GAPS false +enum CHIP_TYPE { + CHIP_WS2812B = 0, + CHIP_SK6812, + CHIP_WS2811, + CHIP_WS2815, + CHIP_UNKNOWN +}; + extern uint32_t whiteTimeout; typedef struct { @@ -39,19 +47,53 @@ typedef struct { int shift; int offset; int powerDiv; - int effSize; + //int effSize; uint8_t bright; uint8_t i2sCh; uint8_t core; uint8_t pin; }LEDSTRIP_SETTINGS; +typedef struct __attribute__((packed)) { + uint8_t cmd; + uint8_t limitedMode; + float temperature; + float vIn; + char profile[10]; + + uint8_t ledChipset1; + char rgbOrder1[4]; // 3 chars + null terminator + uint8_t ledCount1; + uint8_t ledShift1; + uint8_t ledBrightness1; + + uint8_t ledChipset2; + char rgbOrder2[4]; // 3 chars + null terminator + uint8_t ledCount2; + uint8_t ledShift2; + uint8_t ledBrightness2; + + uint8_t frontLightMin; + uint8_t frontLightMax; + uint8_t rearLightMin; + uint8_t rearLightMax; + uint8_t fanLowerTemp; + uint8_t fanUpperTemp; +} USER_SETTINGS; + +enum BOOTH_PROFILE { + PROFILE_CUSTOM=0, + PROFILE_ROAMER, + PROFILE_STIK, + PROFILE_COUNT +}; + extern LEDSTRIP_SETTINGS ledSettings[2]; void RGB_Lights_Control_Task(void *parameters); -void Init_RGB_Lights_Task(void); +void Init_RGB_Lights_Task(bool upgrade); void Init_RGB_Strip(CRGB* leds, uint8_t pin, int size, const String& colorOrder, const String& chipType, uint8_t bright); @@ -72,6 +114,8 @@ void createFirePalette(CRGBPalette16& palette, const COLOR_PACK& colorPack); void loadColorPack(COLOR_PACK& dest, const COLOR_PACK& src); +void SetAndSaveUserSettings(USER_SETTINGS &userSettings); + //void Init_Ramp_Front_Light_Task(void); diff --git a/include/AppUpgrade.h b/include/AppUpgrade.h index a4696f7..e478038 100644 --- a/include/AppUpgrade.h +++ b/include/AppUpgrade.h @@ -8,6 +8,7 @@ #include #include "AppVersion.h" + //#define DEFAULT_MANIFEST_URL "https://storage.googleapis.com/boothifier/latest/" #define DEFAULT_MANIFEST_URL "https://minio.boothwizard.com/boothifier/latest/" #define BUFFER_SIZE 2048 // Reduced from 4096 to use less memory @@ -171,6 +172,7 @@ class AppUpdater { fs::FS& fileSystem; UpdateStatus status; std::unique_ptr downloadBuffer; + size_t downloadBufferSize = 0; /**< Actual size allocated for downloadBuffer */ bool updateAvailable = false; UpdateMode updateMode = UpdateMode::UPDATE_BOTH; // Default to updating both files and firmware @@ -223,7 +225,7 @@ void firmwareUpdateTask(void* param); void startFirmwareUpdateTask(AsyncEventSource* eventSrc); -void loadUpdateJson(void); +bool loadUpdateJson(void); void updateProgress(AppUpdater::UpdateStatus status, int percentage, const char* message); @@ -243,3 +245,5 @@ void setUpdateModeFilesOnly(); void setUpdateModeFirmwareOnly(); void setUpdateModeBoth(); + + diff --git a/include/BLE_SP110E.h b/include/BLE_SP110E.h index db2a470..28e5983 100644 --- a/include/BLE_SP110E.h +++ b/include/BLE_SP110E.h @@ -19,6 +19,11 @@ #define SET_SPEED 0x03 #define SET_AUTO_MODE 0x06 +// My custom commands +#define SET_USER_SETTINGS 0xB0 +#define SET_SHIFT 0xB1 + + // Initializes the BLE server, services, and advertising void Init_BLE_SP110E(NimBLEServer* pServer); diff --git a/include/ColorPalettes.h b/include/ColorPalettes.h index 2df61e1..d8b06bc 100644 --- a/include/ColorPalettes.h +++ b/include/ColorPalettes.h @@ -28,9 +28,9 @@ const COLOR_PACK colorPack_RED_WHITE PROGMEM = { 2, { CRGB::Red, CRGB::White } } const COLOR_PACK colorPack_ORANGE_WHITE PROGMEM = { 2, { CRGB::DarkOrange, CRGB::White } }; const COLOR_PACK colorPack_GREEN_WHITE PROGMEM = { 2, { CRGB::Green, CRGB::White } }; const COLOR_PACK colorPack_BLUE_WHITE PROGMEM = { 2, { CRGB::Blue, CRGB::White } }; -const COLOR_PACK colorPack_PINK_WHITE PROGMEM = { 2, { CRGB::Pink, CRGB::White } }; +const COLOR_PACK colorPack_MAGENTA_WHITE PROGMEM = { 2, { CRGB::Magenta, CRGB::White } }; const COLOR_PACK colorPack_PURPLE_WHITE PROGMEM = { 2, { CRGB::DarkViolet, CRGB::White } }; -const COLOR_PACK colorPack_PURPLE_PINK PROGMEM = { 2, { CRGB::DarkViolet, CRGB::Pink } }; +const COLOR_PACK colorPack_PURPLE_MAGENTA PROGMEM = { 2, { CRGB::DarkViolet, CRGB::Magenta } }; const COLOR_PACK colorPack_PURPLE_YELLOW PROGMEM = { 2, { CRGB::Purple, CRGB::Yellow } }; @@ -45,11 +45,10 @@ const COLOR_PACK colorPack_BLUE_RED PROGMEM = { 2, { CRGB::Blue, CRGB::Red } }; const COLOR_PACK colorPack_ORANGE_BLUE PROGMEM = { 2, { CRGB::DarkOrange, CRGB::Blue } }; const COLOR_PACK colorPack_RED_GREEN PROGMEM = { 2, { CRGB::Red, CRGB::Green } }; const COLOR_PACK colorPack_CYAN_RED PROGMEM = { 2, { CRGB::Cyan, CRGB::Red } }; -const COLOR_PACK colorPack_MAGENTA_GREEN PROGMEM = { 2, { CRGB::Magenta, CRGB::Green } }; // Warm/cool combinations const COLOR_PACK colorPack_ORANGE_CYAN PROGMEM = { 2, { CRGB::DarkOrange, CRGB::Cyan } }; -const COLOR_PACK colorPack_PINK_GREEN PROGMEM = { 2, { CRGB::Pink, CRGB::Green } }; +const COLOR_PACK colorPack_MAGENTA_GREEN PROGMEM = { 2, { CRGB::Magenta, CRGB::Green } }; const COLOR_PACK colorPack_VIOLET_LIME PROGMEM = { 2, { CRGB::DarkViolet, CRGB::Lime } }; // Analogous combinations @@ -67,28 +66,28 @@ const COLOR_PACK double_colorPacks[] PROGMEM = { colorPack_RED_WHITE, colorPack_RED_YELLOW, colorPack_BLUE_WHITE, - colorPack_PINK_WHITE, - colorPack_GREEN_WHITE, colorPack_PURPLE_WHITE, - colorPack_GREEN_YELLOW, - colorPack_PURPLE_PINK, - colorPack_CYAN_RED, - + colorPack_MAGENTA_WHITE, + colorPack_GREEN_WHITE, colorPack_ORANGE_WHITE, + colorPack_PURPLE_MAGENTA, + colorPack_GREEN_YELLOW, + // 9 pack + - colorPack_PURPLE_PINK, + colorPack_CYAN_RED, + colorPack_PURPLE_MAGENTA, colorPack_PURPLE_YELLOW, - colorPack_BLUE_YELLOW, - colorPack_BLUE_GREEN, colorPack_BLUE_RED, colorPack_ORANGE_BLUE, + // 16 pack + + colorPack_RED_GREEN, - colorPack_MAGENTA_GREEN, colorPack_ORANGE_CYAN, - colorPack_PINK_GREEN, colorPack_VIOLET_LIME, colorPack_RED_ORANGE, colorPack_BLUE_PURPLE, @@ -101,12 +100,12 @@ const COLOR_PACK double_colorPacks[] PROGMEM = { // Sectors -const COLOR_PACK colorPack_RAINBOW PROGMEM = { 7, { CRGB::Red, CRGB::OrangeRed, CRGB::Yellow, CRGB::Green, CRGB::Blue, CRGB::BlueViolet, CRGB::MediumVioletRed } }; +const COLOR_PACK colorPack_RAINBOW PROGMEM = { 7, { CRGB::Red, CRGB::DarkOrange, CRGB::LightYellow, CRGB::Green, CRGB::Blue, CRGB::DarkViolet, CRGB::MediumVioletRed } }; // Triple Color Packs, Common Flags const COLOR_PACK colorPack_RED_WHITE_BLUE PROGMEM = { 3, { CRGB::Red, CRGB::White, CRGB::Blue } }; const COLOR_PACK colorPack_RED_WHITE_GREEN PROGMEM = { 3, { CRGB::Red, CRGB::White, CRGB::Green } }; const COLOR_PACK colorPack_RED_YELLOW_BLUE PROGMEM = { 3, { CRGB::Red, CRGB::Yellow, CRGB::Blue } }; -const COLOR_PACK colorPack_RED_ORANGE_YELLOW PROGMEM = { 3, { CRGB::Red, CRGB::DarkOrange, CRGB::Yellow } }; +const COLOR_PACK colorPack_RED_ORANGE_YELLOW PROGMEM = { 3, { CRGB::Red, CRGB::DarkOrange, CRGB::Yellow } }; const COLOR_PACK colorPack_RED_YELLOW_GREEN PROGMEM = { 3, { CRGB::Red, CRGB::Yellow, CRGB::Green } }; const COLOR_PACK colorPack_RED_PURPLE_BLUE PROGMEM = { 3, { CRGB::Red, CRGB::Purple, CRGB::Blue } }; @@ -114,13 +113,11 @@ const COLOR_PACK colorPack_GREEN_WHITE_RED PROGMEM = { 3, { CRGB::Green, CRGB:: const COLOR_PACK colorPack_GREEN_WHITE_ORANGE PROGMEM = { 3, { CRGB::Green, CRGB::White, CRGB::DarkOrange } }; const COLOR_PACK colorPack_GREEN_WHITE_BLUE PROGMEM = { 3, { CRGB::Green, CRGB::White, CRGB::Blue } }; - -const COLOR_PACK colorPack_BLUE_WHITE_GREEN PROGMEM = { 3, { CRGB::Blue, CRGB::White, CRGB::Green } }; const COLOR_PACK colorPack_BLUE_YELLOW_GREEN PROGMEM = { 3, { CRGB::Blue, CRGB::Yellow, CRGB::Green } }; const COLOR_PACK colorPack_BLUE_YELLOW_RED PROGMEM = { 3, { CRGB::Blue, CRGB::Yellow, CRGB::Red } }; // Additional triple color combinations -const COLOR_PACK colorPack_PURPLE_PINK_CYAN PROGMEM = { 3, { CRGB::Purple, CRGB::Pink, CRGB::Cyan } }; +const COLOR_PACK colorPack_MAGENTA_WHITE_CYAN PROGMEM = { 3, { CRGB::Magenta, CRGB::White, CRGB::Cyan } }; const COLOR_PACK colorPack_ORANGE_YELLOW_LIME PROGMEM = { 3, { CRGB::DarkOrange, CRGB::Yellow, CRGB::Lime } }; const COLOR_PACK colorPack_MAGENTA_YELLOW_CYAN PROGMEM = { 3, { CRGB::Magenta, CRGB::Yellow, CRGB::Cyan } }; const COLOR_PACK colorPack_LIME_CYAN_MAGENTA PROGMEM = { 3, { CRGB::Lime, CRGB::Cyan, CRGB::Magenta } }; @@ -149,27 +146,30 @@ const COLOR_PACK tripple_colorPacks[] PROGMEM = { colorPack_GREEN_WHITE_ORANGE, colorPack_BLUE_YELLOW_GREEN, colorPack_RED_GREEN_BLUE, - colorPack_PURPLE_PINK_CYAN, + colorPack_MAGENTA_WHITE_CYAN, colorPack_YELLOW_ORANGE_RED, colorPack_BLUE_CYAN_LIME, - colorPack_PINK_PURPLE_MAGENTA, - colorPack_RED_YELLOW_BLUE, + // 9 pack + + colorPack_RED_ORANGE_YELLOW, colorPack_RED_YELLOW_GREEN, colorPack_RED_PURPLE_BLUE, colorPack_GREEN_WHITE_RED, colorPack_GREEN_WHITE_BLUE, - colorPack_BLUE_WHITE_GREEN, colorPack_BLUE_YELLOW_RED, + colorPack_GREEN_CYAN_BLUE, + // 16 pack + + colorPack_ORANGE_YELLOW_LIME, colorPack_MAGENTA_YELLOW_CYAN, colorPack_LIME_CYAN_MAGENTA, colorPack_RED_ORANGE_PINK, colorPack_PURPLE_BLUE_CYAN, - colorPack_GREEN_CYAN_BLUE, colorPack_YELLOW_PURPLE_ORANGE, - colorPack_PINK_LIME_PURPLE + }; const COLOR_PACK colorPack_grad_blueish PROGMEM = { 3, { CRGB::Blue, CRGB::Cyan, CRGB::Green } }; @@ -200,7 +200,7 @@ const COLOR_PACK colorPack_Single_Viloet PROGMEM = { 1, { CRGB::DarkViolet } }; const COLOR_PACK colorPack_Single_Magenta PROGMEM = { 1, { CRGB::Magenta } }; const COLOR_PACK colorPack_Single_White PROGMEM = { 1, { CRGB::White } }; -// 9 Single Color Packs +// 8 Single Color Packs const COLOR_PACK single_colorPacks[] PROGMEM = { colorPack_Single_White, colorPack_Single_Red, diff --git a/include/PWM_Output.h b/include/PWM_Output.h index 8cf92c2..21d5978 100644 --- a/include/PWM_Output.h +++ b/include/PWM_Output.h @@ -38,6 +38,8 @@ class PWM_Output { float standardFactor; float visionFactor; + int8_t pin; + bool initialized = false; }; diff --git a/include/Ramp_Lights.h b/include/Ramp_Lights.h index 4210ff6..edbdabc 100644 --- a/include/Ramp_Lights.h +++ b/include/Ramp_Lights.h @@ -18,7 +18,7 @@ private: float currentValue; bool IsOn = false; RAMP_STATE rampState; - int tickCount; + int tickCount = 0; void tick(); void singleClick(); diff --git a/include/global.h b/include/global.h index f29adc0..71f5d70 100644 --- a/include/global.h +++ b/include/global.h @@ -60,3 +60,5 @@ void Log_CPU_Load(void); void print_task_watermarks(void); +float updateLowpass(float currentValue, float newValue, float alpha); + diff --git a/include/my_device.h b/include/my_device.h index a9ae4f9..f6a6581 100644 --- a/include/my_device.h +++ b/include/my_device.h @@ -9,6 +9,10 @@ extern SYS_SETTINGS sys_settings; extern PWM_Output *pwmOutputs[4]; extern RAMP_LIGHT *rampLight1; extern RAMP_LIGHT *rampLight2; +extern String booth_file_path; +extern float PowerVin; +extern float PowerVinAlpha; +extern float prevPowerVin; void Init_ADC(void); float readBoardInputVoltage(void); diff --git a/include/my_wifi.h b/include/my_wifi.h index 2745c16..3de48b2 100644 --- a/include/my_wifi.h +++ b/include/my_wifi.h @@ -23,7 +23,7 @@ void handleGET_Query(AsyncWebServerRequest *request); void handleFilesUpload_OnBody(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); -void sendHtmlFile(const char* filePath, AsyncWebServerRequest *request, String (*callback)(const String&)); +bool sendHtmlFile(const char* filePath, AsyncWebServerRequest *request, String (*callback)(const String&)); String fileManagerHtmlProcessor(const String& var); String HomeHtmlProcessor(const String& var); String listDirAsHtml(String directoryList[], int count); diff --git a/include/system.h b/include/system.h index ad74af9..8e96366 100644 --- a/include/system.h +++ b/include/system.h @@ -5,6 +5,9 @@ #include #include "ATALights.h" + +enum LED_CHIPSET { LED_CHIPSET_WS2812B=0, LED_CHIPSET_SK6812=1, LED_CHIPSET_WS2811_400=2, LED_CHIPSET_WS2815=3, LED_CHIPSET_NONE=255 }; + typedef struct { bool enabled; }BTN_SETTINGS; @@ -79,6 +82,8 @@ typedef struct { enum BOOTH_MODE { BOOTH_MODE_NONE=0, BOOTH_MODE_ROAMER=1, BOOTH_MODE_STIK=2 }; typedef struct { + String profile; + bool limitedMode; BOOTH_MODE mode; BOARD_PINS boardPins; BTN_SETTINGS btnSettings[3]; diff --git a/platformio.ini b/platformio.ini index 9ff1f0c..04331e5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -24,6 +24,7 @@ lib_deps = jeremycole/I2C Temperature Sensors derived from the LM75 @ ^1.0.3 mathertel/OneButton @ ^2.6.1 h2zero/NimBLE-Arduino @ ^1.4.1 + #h2zero/NimBLE-Arduino @ ^2.3.6 adafruit/Adafruit SSD1306 @ ^2.5.7 fastled/FastLED @ ^3.9.4 marian-craciunescu/ESP32Ping@^1.7 @@ -35,6 +36,11 @@ build_flags = #-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO -D CONFIG_ARDUHAL_LOG_COLORS=1 + #-Os + #-ffunction-sections + #-fdata-sections + #-Wl,--gc-sections + upload_port = COM5 debug_init_break = tbreak setup monitor_port = COM5 diff --git a/src/ATALights.cpp b/src/ATALights.cpp index faeacde..1ee214a 100644 --- a/src/ATALights.cpp +++ b/src/ATALights.cpp @@ -9,16 +9,16 @@ #include "system.h" #include "ColorPalettes.h" #include "global.h" -//#include #include "PWM_Output.h" #include "my_device.h" #include "system.h" #include "my_device.h" +#include "LittleFS.h" #define FASTLED_CORE 0 static const char* tag = "strips"; -uint32_t whiteTimeout = 0; +//uint32_t whiteTimeout = 0; TaskHandle_t Animation_Task_Handle; TaskHandle_t Ramp_Front_Light_Task_Handle; @@ -27,7 +27,13 @@ volatile bool AnimationLooping = false; ANIM_EVENT prevAnimEvent = {0}; QueueHandle_t animationQueue = xQueueCreate( 4, sizeof( ANIM_EVENT ) ); -bool fillAnimationActive = false; +bool upgradeMode = false; + +#define LIMITED_ANIMATION true + +#define DEFAULT_ANIMATION 23 + +//bool fillAnimationActive = false; void RGB_Lights_Set_Animation(int animIndex, uint8_t red, uint8_t grn, uint8_t blu){ @@ -47,7 +53,8 @@ void RGB_Lights_Set_Animation(int animIndex, uint8_t red, uint8_t grn, uint8_t b } void RGB_Animations_ON(){ - RGB_Lights_Set_Animation(prevAnimEvent.AnimationIndex, prevAnimEvent.data.red, prevAnimEvent.data.grn, prevAnimEvent.data.blu); + //RGB_Lights_Set_Animation(prevAnimEvent.AnimationIndex, prevAnimEvent.data.red, prevAnimEvent.data.grn, prevAnimEvent.data.blu); + RGB_Lights_Set_Animation(DEFAULT_ANIMATION, 0, 0, 0); // set comet rainbow animation } void RGB_Animations_OFF(){ @@ -63,7 +70,9 @@ void Lights_Set_White(uint8_t val){ //pwmOut[0]->setOutput(val / 2.5f); } -void Init_RGB_Lights_Task(void){ + +void Init_RGB_Lights_Task(bool upgrade){ + upgradeMode = upgrade; 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); ESP_LOGD(tag, "Initializing Strip1: Pin: %d, size: %d, order: %s, chip: %s", ledSettings[0].pin, ledSettings[0].size, ledSettings[0].rgbOrder, ledSettings[0].chip); @@ -234,31 +243,61 @@ inline int calcPixelIndex(LEDSTRIP_SETTINGS& strip, int index) { return (x +strip.offset) % strip.effSize; } */ +// ...existing code... +inline void setPixel1(LEDSTRIP_SETTINGS& leds, int pixelIndex, const CRGB col) { + // Guard against invalid configuration that can cause crashes (null pointer or zero size) + if (leds.size <= 0 || leds.leds == nullptr) { + ESP_LOGW(tag, "setPixel1: invalid strip (Size=%d, leds=%p)", leds.size, (void*)leds.leds); + return; + } + // Use a signed type so negative pixelIndex is preserved + int x = pixelIndex + leds.shift; + int n = leds.size; + + // If strip.effSize is power of 2: (n & (n - 1)) == 0 + int idx; + if ((n & (n - 1)) == 0) { + // Masking is safe if we treat x as unsigned for masking, + // this yields the correct wrapped index for two's-complement + idx = static_cast( (static_cast(x)) & (static_cast(n) - 1u) ); + } else { + // General modulo: C++ '%' can be negative, so normalize + idx = x % n; + if (idx < 0) idx += n; + } + + // Normalize final position robustly (handles negative offsets) + int pos = (idx + leds.offset) % n; + if (pos < 0) pos += n; + + leds.leds[pos] = col; +} +/* inline void setPixel1(LEDSTRIP_SETTINGS& leds, int pixelIndex, const CRGB col) { register uint16_t x = pixelIndex + ledSettings[0].shift; - // If strip.effSize is power of 2, use faster bit masking - if ((leds.effSize & (leds.effSize - 1)) == 0) { - x = (x < 0) ? ((x + leds.effSize) & (leds.effSize - 1)) : (x & (leds.effSize - 1)); - leds.leds[(x + leds.offset) & (leds.effSize - 1)] = col; + // If strip.size is power of 2, use faster bit masking + if ((leds.size & (leds.size - 1)) == 0) { + x = (x < 0) ? ((x + leds.size) & (leds.size - 1)) : (x & (leds.size - 1)); + leds.leds[(x + leds.offset) & (leds.size - 1)] = col; } else { // For non-power-of-2 sizes, still need modulo - x = (x < 0) ? ((x + ledSettings[0].effSize) % ledSettings[0].effSize) : (x % ledSettings[0].effSize); - ledSettings[0].leds[(x + ledSettings[0].offset) % ledSettings[0].effSize] = col; + x = (x < 0) ? ((x + ledSettings[0].size) % ledSettings[0].size) : (x % ledSettings[0].size); + ledSettings[0].leds[(x + ledSettings[0].offset) % ledSettings[0].size] = col; } } - +*/ inline void setPixel2(int pixelIndex, const CRGB col) { register uint16_t x = pixelIndex + ledSettings[1].shift; - // If strip.effSize is power of 2, use faster bit masking - if ((ledSettings[1].effSize & (ledSettings[1].effSize - 1)) == 0) { - x = (x < 0) ? ((x + ledSettings[1].effSize) & (ledSettings[1].effSize - 1)) : (x & (ledSettings[1].effSize - 1)); - ledSettings[1].leds[(x + ledSettings[1].offset) & (ledSettings[1].effSize - 1)] = col; + // If strip.size is power of 2, use faster bit masking + if ((ledSettings[1].size & (ledSettings[1].size - 1)) == 0) { + x = (x < 0) ? ((x + ledSettings[1].size) & (ledSettings[1].size - 1)) : (x & (ledSettings[1].size - 1)); + ledSettings[1].leds[(x + ledSettings[1].offset) & (ledSettings[1].size - 1)] = col; } else { // For non-power-of-2 sizes, still need modulo - x = (x < 0) ? ((x + ledSettings[1].effSize) % ledSettings[1].effSize) : (x % ledSettings[1].effSize); - ledSettings[1].leds[(x + ledSettings[1].offset) % ledSettings[1].effSize] = col; + x = (x < 0) ? ((x + ledSettings[1].size) % ledSettings[1].size) : (x % ledSettings[1].size); + ledSettings[1].leds[(x + ledSettings[1].offset) % ledSettings[1].size] = col; } } @@ -286,7 +325,7 @@ void Init_RGB_Strip(CRGB* leds, uint8_t pin, int size, const String& colorOrder, if(pin == 3){ // First level: Chip type selection - if (chipUpper == "WS2812B" || chipUpper == "SK6812") { + if (chipUpper == "WS2812B") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; @@ -308,7 +347,7 @@ void Init_RGB_Strip(CRGB* leds, uint8_t pin, int size, const String& colorOrder, default: FastLED.addLeds(leds, size); break; } } - else if (chipUpper == "WS2811_400") { + else if (chipUpper == "WS2811") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; @@ -361,7 +400,7 @@ void Init_RGB_Strip(CRGB* leds, uint8_t pin, int size, const String& colorOrder, default: FastLED.addLeds(leds, size); break; } } - else if (chipUpper == "WS2811_400") { + else if (chipUpper == "WS2811") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; @@ -392,7 +431,7 @@ void Init_RGB_Strip(CRGB* leds, uint8_t pin, int size, const String& colorOrder, } else if(pin == 46){ // First level: Chip type selection - if (chipUpper == "WS2812B" || chipUpper == "SK6812") { + if (chipUpper == "WS2812B") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; @@ -414,7 +453,7 @@ void Init_RGB_Strip(CRGB* leds, uint8_t pin, int size, const String& colorOrder, default: FastLED.addLeds(leds, size); break; } } - else if (chipUpper == "WS2811_400") { + else if (chipUpper == "WS2811") { switch(rgbOrder) { case RGB: FastLED.addLeds(leds, size); break; case RBG: FastLED.addLeds(leds, size); break; @@ -439,7 +478,7 @@ void Init_RGB_Strip(CRGB* leds, uint8_t pin, int size, const String& colorOrder, else { // Default to WS2812B if unknown chip type ESP_LOGW(tag, "Unknown LED chip type: %s, defaulting to WS2812B", chipType.c_str()); - FastLED.addLeds(leds, size); + FastLED.addLeds(leds, size); } ESP_LOGI(tag, "Initialized %s LED strip with %d LEDs on pin %d", chipType.c_str(), size, pin); } @@ -449,147 +488,392 @@ void Init_RGB_Strip(CRGB* leds, uint8_t pin, int size, const String& colorOrder, void RGB_Lights_Control_Task(void *parameters){ + // Wait for other tasks to initialize + vTaskDelay(pdMS_TO_TICKS(200)); // wait for everything to settle + RGB_Lights_Set_Brightness(ledSettings[0].bright); + + if(upgradeMode){ + // fill with 3 colors equally magenta, cyan, lime + RGB_Lights_Set_Brightness(64); + fill_gradient_RGB(ledSettings[0].leds, ledSettings[0].size, CRGB(CRGB::Magenta), CRGB(CRGB::Cyan), CRGB(CRGB::Lime), CRGB(CRGB::Magenta)); + FastLED.show(); + }else{ + RGB_Lights_Set_Animation(DEFAULT_ANIMATION, 0, 0, 0); // set comet rainbow animation + } ANIM_EVENT AnimEvent; - CRGB col; - COLOR_PACK colorPack; - CRGBPalette16 firePalette; + + if (LIMITED_ANIMATION){ + while (true) { + if (xQueueReceive(animationQueue, &AnimEvent, portMAX_DELAY) == pdTRUE) { + ESP_LOGD(tag, "New Animation Event: Index: %d", AnimEvent.AnimationIndex); + switch (AnimEvent.AnimationIndex) { - // Wait for other tasks to initialize (including front light task) - vTaskDelay(pdMS_TO_TICKS(500)); // wait for everything to settle - - RGB_Lights_Set_Brightness(48); - RGB_Lights_Set_Animation(23, 0, 0, 0); // set comet rainbow animation - - - while (true) { - if (xQueueReceive(animationQueue, &AnimEvent, portMAX_DELAY) == pdTRUE) { - ESP_LOGI(tag, "New Animation Event: Index: %d", AnimEvent.AnimationIndex); - switch (AnimEvent.AnimationIndex) { - case -3: // Set Pixel by index - if (AnimEvent.data.data[7] >= 0 && AnimEvent.data.data[7] < ledSettings[0].size) { - ledSettings[0].leds[AnimEvent.data.data[7]] = CRGB(AnimEvent.data.red, AnimEvent.data.grn, AnimEvent.data.blu); + case -3: // Set Shift + if (AnimEvent.data.data[0] >= 0 && AnimEvent.data.data[0] < ledSettings[0].size) { + fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB::Black); + ledSettings[0].shift = AnimEvent.data.data[0]; + vTaskDelay(25 / portTICK_PERIOD_MS); + setPixel1(ledSettings[0], 0, CRGB::White * FastLED.getBrightness() / 255); + FastLED.show(); + ESP_LOGD(tag, "Set Shift: %d", ledSettings[0].shift); + } else { + ESP_LOGW(tag, "Pixel index out of range: %d", AnimEvent.data.data[0]); + } + break; + case -2: // Fill Static Color + fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB(AnimEvent.data.red, AnimEvent.data.grn, AnimEvent.data.blu)); FastLED.show(); - } else { - ESP_LOGW(tag, "Pixel index out of range: %d", AnimEvent.data.data[7]); + ESP_LOGD(tag, "Static Color"); + break; + case -1: + FastLED.clear(); + FastLED.show(); + ESP_LOGD(tag, "LEDs Off"); + break; + case 0: + fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB::Black); + FastLED.show(); + break; + case 1 ... 5: { // Timed Fill Animations + int timeDuration = AnimEvent.AnimationIndex * 1000 - 400; + int whiteDelay = timeDuration - 1000; + if (whiteDelay < 800) whiteDelay = 800; // minimum 8 seconds + 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); + break; } - break; - case -2: // Fill Static Color - col = CRGB(AnimEvent.data.red, AnimEvent.data.grn, AnimEvent.data.blu); - fill_solid(ledSettings[0].leds, ledSettings[0].size, col); - FastLED.show(); - ESP_LOGD(tag, "Static Color"); - break; - case -1: - FastLED.clear(); - FastLED.show(); - ESP_LOGD(tag, "LEDs Off"); - break; - case 0: - fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB::Black); - FastLED.show(); - break; - case 1: case 2: case 3: case 4: case 5:{ // Timed Fill Animations - int timeDuration = AnimEvent.AnimationIndex * 1000; - int whiteDelay = timeDuration - 1000; - 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); - break; - } - case 6: - // RGB White and Dedicated White all on with timeout and brightness reduction - if (pwmOutputs[0] != nullptr) { + case 6: + // 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); + break; + case 7: + Anim_Rainbow(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60); + break; + case 8 ... 12: + Anim_GradientRotate(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, gradient_colorPack[AnimEvent.AnimationIndex - 8], 80); + break; + case 13 ... 17: { // Fire Animations + COLOR_PACK fp = fireColorPacks[AnimEvent.AnimationIndex - 13]; // copy const pack to mutable + CRGBPalette16 firePalette; + createFirePalette(firePalette, fp); + Anim_Fire(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60, firePalette, ledSettings[0].shift); + break; } - break; - case 7: - Anim_Rainbow(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60); - break; - case 8: case 9: case 10: case 11: case 12: - Anim_GradientRotate(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, gradient_colorPack[AnimEvent.AnimationIndex - 8], 80); - break; - case 13: case 14: case 15: case 16: case 17: { // Fire Animations - COLOR_PACK fp = fireColorPacks[AnimEvent.AnimationIndex - 13]; // copy const pack to mutable - createFirePalette(firePalette, fp); - Anim_Fire(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60, firePalette, ledSettings[0].shift); - break; + case 18 ... 20: // Sparkle/Twinkle + Anim_Sparkle(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[0], 40, 20); + break; + case 21: + Anim_ColorBreath(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 7000, 90); + break; + case 22: // Rain Animation + Anim_Morph(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 20, 40); + break; + + // Comets + case 23: + Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 40, 85, RANDOM_DECAY, 1); + break; + case 24 ... 31: + Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 24], 40, 85, RANDOM_DECAY, 6); + break; + case 32 ... 40: + Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 32], 40, 85, RANDOM_DECAY, 3); + break; + case 41 ... 49: + Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 41], 40, 85, RANDOM_DECAY, 2); + break; + + // Snakes + case 50: + Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 50); + break; + case 51 ... 58: + Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 51], 60, 6); + break; + case 59 ... 67: + Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 59], 60, 3); + break; + case 68 ... 76: + Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 68], 60, 2); + break; + + // Sectors + case 77: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, NO_GAPS, 1, 40, 90); + break; + case 78 ... 86: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 78], NO_GAPS, 3, 40, 90); + break; + case 87 ... 95: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 87], NO_GAPS, 2, 40, 90); + break; + + // Dashes + case 96: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, WITH_GAPS, 1, 40, 90); + break; + case 97 ... 104: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 97], WITH_GAPS, 6, 40, 90); + break; + case 105 ... 113: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 105], WITH_GAPS, 3, 40, 90); + break; + case 114 ... 122: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 114], WITH_GAPS, 2, 40, 90); + break; + default: + ESP_LOGW(tag, "Loop default"); + break; } - case 18: case 19: case 20:// Sparkle/Twinkle - Anim_Sparkle(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[0], 40, 20); - break; - case 21: - //Anim_ColorBreath(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 7000, 90); - Anim_Morph(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 20, 40); - break; - case 22: // Rain Animation - break; - - // Comets - case 23: - Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 40, 85, RANDOM_DECAY, 1); - break; - case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: - Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 24], 40, 85, RANDOM_DECAY, 6); - break; - case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: - Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 32], 40, 85, RANDOM_DECAY, 3); - break; - case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: - Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 41], 40, 85, RANDOM_DECAY, 2); - break; - - // Snakes - case 50: - Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 50); - break; - case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: - Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 51], 60, 6); - break; - case 59: case 60: case 61: case 62: case 63: case 64: case 65: case 66: case 67: - Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 59], 60, 3); - break; - case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: - Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 68], 60, 2); - break; - - // Sectors - case 77: - Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, NO_GAPS, 1, 40, 90); - break; - case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: - Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 78], NO_GAPS, 3, 40, 90); - break; - case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: - Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 87], NO_GAPS, 2, 40, 90); - break; - - // Dashes - case 96: - Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, WITH_GAPS, 1, 40, 90); - break; - case 97:case 98:case 99: case 100: case 101: case 102: case 103: case 104: - Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 97], WITH_GAPS, 6, 40, 90); - break; - case 105: case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: - Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 105], WITH_GAPS, 3, 40, 90); - break; - case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: - Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 114], WITH_GAPS, 2, 40, 90); - break; - - default: - ESP_LOGW(tag, "Loop default"); - break; + AnimationLooping = false; + prevAnimEvent = AnimEvent; + ESP_LOGD(tag, "Going to Queue to Wait"); } + } + } else { + // Extended Animation Set + while (true) { + if (xQueueReceive(animationQueue, &AnimEvent, portMAX_DELAY) == pdTRUE) { + ESP_LOGD(tag, "New Animation Event: Index: %d", AnimEvent.AnimationIndex); + switch (AnimEvent.AnimationIndex) { + case -3: // Set Shift + if (AnimEvent.data.data[0] >= 0 && AnimEvent.data.data[0] < ledSettings[0].size) { + fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB::Black); + ledSettings[0].shift = AnimEvent.data.data[0]; - AnimationLooping = false; - prevAnimEvent = AnimEvent; - ESP_LOGD(tag, "Going to Queue to Wait"); + ESP_LOGD(tag, "Set Shift: %d", ledSettings[0].shift); + vTaskDelay(25 / portTICK_PERIOD_MS); + setPixel1(ledSettings[0], 0, CRGB::White); + + FastLED.show(); + } else { + ESP_LOGW(tag, "Pixel index out of range: %d", AnimEvent.data.data[0]); + } + break; + case -2: // Fill Static Color + fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB(AnimEvent.data.red, AnimEvent.data.grn, AnimEvent.data.blu)); + FastLED.show(); + ESP_LOGD(tag, "Static Color"); + break; + case -1: + FastLED.clear(); + FastLED.show(); + ESP_LOGD(tag, "LEDs Off"); + break; + case 0: + fill_solid(ledSettings[0].leds, ledSettings[0].size, CRGB::Black); + FastLED.show(); + break; + case 1 ... 5: { // Timed Fill Animations + int timeDuration = AnimEvent.AnimationIndex * 1000 - 400; + int whiteDelay = timeDuration - 1000; + if (whiteDelay < 800) whiteDelay = 800; // minimum 8 seconds + 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); + break; + } + case 6: + // 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); + break; + case 7: + Anim_Rainbow(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60); + break; + case 8 ... 12: + Anim_GradientRotate(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, gradient_colorPack[AnimEvent.AnimationIndex - 8], 80); + break; + case 13 ... 17: { // Fire Animations + COLOR_PACK fp = fireColorPacks[AnimEvent.AnimationIndex - 13]; // copy const pack to mutable + CRGBPalette16 firePalette; + createFirePalette(firePalette, fp); + Anim_Fire(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, 60, firePalette, ledSettings[0].shift); + break; + } + case 18 ... 20: // Sparkle/Twinkle + Anim_Sparkle(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[0], 40, 20); + break; + case 21: + Anim_ColorBreath(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 7000, 90); + break; + case 22: // Rain Animation + Anim_Morph(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 20, 40); + break; + + // Comets + case 23: + Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 40, 85, RANDOM_DECAY, 1); + break; + case 24 ... 31: + Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 24], 40, 85, RANDOM_DECAY, 6); + break; + case 32 ... 47: + Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 32], 40, 85, RANDOM_DECAY, 3); + break; + case 48 ... 63: + Anim_Comets(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 48], 40, 85, RANDOM_DECAY, 2); + break; + + // Snakes + case 64: + Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, 50); + break; + case 65 ... 72: + Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 65], 60, 6); + break; + case 73 ... 88: + Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 73], 60, 3); + break; + case 89 ... 104: + Anim_Snakes(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 89], 60, 2); + break; + + // Sectors + case 105: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, NO_GAPS, 1, 40, 90); + break; + case 106 ... 121: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 106], NO_GAPS, 3, 40, 90); + break; + case 122 ... 137: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 122], NO_GAPS, 2, 40, 90); + break; + + // Dashes + case 138: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, colorPack_RAINBOW, WITH_GAPS, 1, 40, 90); + break; + case 139 ... 146: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, single_colorPacks[AnimEvent.AnimationIndex - 139], WITH_GAPS, 6, 40, 90); + break; + case 147 ... 162: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, double_colorPacks[AnimEvent.AnimationIndex - 147], WITH_GAPS, 3, 40, 90); + break; + case 163 ... 178: + Anim_Color_Sectors(AnimationLooping, ledSettings[0].leds, ledSettings[0].size, tripple_colorPacks[AnimEvent.AnimationIndex - 163], WITH_GAPS, 2, 40, 90); + break; + default: + ESP_LOGW(tag, "Loop default"); + break; + } + + AnimationLooping = false; + prevAnimEvent = AnimEvent; + ESP_LOGD(tag, "Going to Queue to Wait"); + } } } } +void SetAndSaveUserSettings(USER_SETTINGS &userSettings) { + + // Apply the settings to sys_settings + sys_settings.limitedMode = userSettings.limitedMode; + + sys_settings.ledStripSettings[0]->chip = userSettings.ledChipset1; + sys_settings.ledStripSettings[0]->shift = userSettings.ledShift1; + sys_settings.ledStripSettings[0]->bright = userSettings.ledBrightness1; + RGB_Lights_Set_Brightness(userSettings.ledBrightness1); + + sys_settings.ledStripSettings[0]->chip = userSettings.ledChipset2; + sys_settings.ledStripSettings[0]->shift = userSettings.ledShift2; + sys_settings.ledStripSettings[0]->bright = userSettings.ledBrightness2; + + sys_settings.tSensorSettings.setpoint1 = userSettings.fanLowerTemp; + sys_settings.tSensorSettings.setpoint2 = userSettings.fanUpperTemp; + sys_settings.rampLightSettings[0].min = userSettings.frontLightMin; + sys_settings.rampLightSettings[0].max = userSettings.frontLightMax; + sys_settings.rampLightSettings[1].min = userSettings.rearLightMin; + sys_settings.rampLightSettings[1].max = userSettings.rearLightMax; + + if (!LittleFS.begin()) { + ESP_LOGE(tag, "Failed to mount file system"); + return; + } + + // First, open the existing file for reading so we preserve unrelated keys + File file = LittleFS.open(booth_file_path, "r"); + JsonDocument jsonDocument; + + if (file) { + // Try to deserialize existing content; if it fails, start with an empty document + DeserializationError err = deserializeJson(jsonDocument, file); + if (err) { + ESP_LOGW(tag, "Failed to parse existing JSON (%s), starting fresh", err.c_str()); + jsonDocument.clear(); + } + file.close(); + } else { + ESP_LOGW(tag, "Settings file not found, a new one will be created"); + } + + // Update only the keys we care about + jsonDocument["limied-mode"] = userSettings.limitedMode; + + jsonDocument["ramp-lights"][0]["min"] = userSettings.frontLightMin; + jsonDocument["ramp-lights"][0]["max"] = userSettings.frontLightMax; + jsonDocument["ramp-lights"][1]["min"] = userSettings.rearLightMin; + jsonDocument["ramp-lights"][1]["max"] = userSettings.rearLightMax; + + String chipName = "Unknown"; + if (userSettings.ledChipset1 == CHIP_WS2812B) chipName = "WS2812B"; + else if (userSettings.ledChipset1 == CHIP_SK6812) chipName = "SK6812"; + else if (userSettings.ledChipset1 == CHIP_WS2811) chipName = "WS2811"; + else if (userSettings.ledChipset1 == CHIP_WS2815) chipName = "WS2815"; + jsonDocument["strips"][0]["chip"] = chipName; + userSettings.rgbOrder1[3] = '\0'; // Ensure null-terminated string + jsonDocument["strips"][0]["rgb-order"] = String(userSettings.rgbOrder1); + jsonDocument["strips"][0]["shift"] = userSettings.ledShift1; + jsonDocument["strips"][0]["bright"] = userSettings.ledBrightness1; + jsonDocument["strips"][0]["count"] = userSettings.ledCount1; + + + if (userSettings.ledChipset2 == CHIP_WS2812B) chipName = "WS2812B"; + else if (userSettings.ledChipset2 == CHIP_SK6812) chipName = "SK6812"; + else if (userSettings.ledChipset2 == CHIP_WS2811) chipName = "WS2811"; + else if (userSettings.ledChipset2 == CHIP_WS2815) chipName = "WS2815"; + jsonDocument["strips"][1]["chip"] = chipName; + userSettings.rgbOrder2[3] = '\0'; // Ensure null-terminated string + jsonDocument["strips"][1]["rgb-order"] = String(userSettings.rgbOrder2); + jsonDocument["strips"][1]["shift"] = userSettings.ledShift2; + jsonDocument["strips"][1]["bright"] = userSettings.ledBrightness2; + jsonDocument["strips"][1]["count"] = userSettings.ledCount2; + + jsonDocument["t-sensor"]["sp1"] = userSettings.fanLowerTemp; + jsonDocument["t-sensor"]["sp2"] = userSettings.fanUpperTemp; + + //jsonDocument["stripsr"][0]["chip"] = settings.ledChipset; + + // Now open the file for writing (overwrite) and serialize back + File out = LittleFS.open(booth_file_path, "w"); + if (!out) { + ESP_LOGE(tag, "Failed to open file for writing"); + return; + } + + if (serializeJson(jsonDocument, out) == 0) { + ESP_LOGE(tag, "Failed to write to file"); + } else { + ESP_LOGI(tag, "User settings saved successfully"); + } + + out.close(); + + + // Modify system.json with booth type + String sysProf = String(sys_settings.profile); + String userProf = String(userSettings.profile); + sysProf.toLowerCase(); + userProf.toLowerCase(); + ESP_LOGI(tag, "System Profile: '%s', User Profile: '%s'", sysProf.c_str(), userProf.c_str()); + + if (userProf.length() > 0 && sysProf.indexOf(userProf) >= 0) { + // userSettings.profile is contained in sys_settings.profile (case-insensitive) + } + +} + + void createFirePalette(CRGBPalette16& palette, const COLOR_PACK& colorPack) { for (uint8_t i = 0; i < 16; i++) { if (i < 3) palette[i] = CRGB::Black; diff --git a/src/Animations.cpp b/src/Animations.cpp index 430ac81..b59d15e 100644 --- a/src/Animations.cpp +++ b/src/Animations.cpp @@ -27,6 +27,7 @@ void Animation_Init(void){ } // Animation Loop Template +/* void Animation_Loop(bool volatile& loop_active_flag, int speed, std::function callback) { if (!callback) { ESP_LOGE("Animation_Loop", "Invalid callback function"); @@ -65,7 +66,62 @@ void Animation_Loop(bool volatile& loop_active_flag, int speed, std::function callback) { + if (!callback) { + ESP_LOGE("Animation_Loop", "Invalid callback function"); + return; + } + loop_active_flag = true; + speed = constrain(speed, 0, MaxSpeed); + + // compute desired loop delay in milliseconds and clamp + int loopDelayMs = max(MaxSpeed - speed, MinLoopDelay); + const int MAX_LOOP_DELAY_MS = 60 * 1000; // 60s safety cap + if (loopDelayMs > MAX_LOOP_DELAY_MS) loopDelayMs = MAX_LOOP_DELAY_MS; + + // Convert ms -> RTOS ticks + TickType_t loopDelayTicks = pdMS_TO_TICKS(loopDelayMs); + + ulTaskNotifyTake(pdTRUE, 0); // Clear any pending notifications + + TickType_t xLastWakeTime; + TickType_t elapsedTicks; + TickType_t delayTicks; + int retVal = 0; + while(!retVal && loop_active_flag) { + xLastWakeTime = xTaskGetTickCount(); + + try { + retVal = callback(); // Call animation function + } catch (const std::exception& e) { + ESP_LOGE("Animation_Loop", "Callback exception: %s", e.what()); + break; + } catch (...) { + ESP_LOGE("Animation_Loop", "Callback unknown exception"); + break; + } + + if(!loop_active_flag) break; + + // compute elapsed ticks since callback start and remaining ticks + elapsedTicks = xTaskGetTickCount() - xLastWakeTime; + delayTicks = (elapsedTicks < loopDelayTicks) ? (loopDelayTicks - elapsedTicks) : 0; + + if (delayTicks == 0) { + // yield a tick to avoid busy-spin + vTaskDelay(1); + if (ulTaskNotifyTake(pdTRUE, 0)) break; // notified -> exit + } else { + if (ulTaskNotifyTake(pdTRUE, delayTicks)) { break; } // notified -> exit + } + } + + loop_active_flag = false; +} + +/* void Animation_Loop_Variable(bool volatile& loop_active_flag, std::function callback) { if (!callback) { ESP_LOGE("Animation_Loop", "Invalid callback function"); @@ -105,8 +161,74 @@ void Animation_Loop_Variable(bool volatile& loop_active_flag, std::function callback) { + if (!callback) { + ESP_LOGE("Animation_Loop", "Invalid callback function"); + return; + } + + loop_active_flag = true; + + // clear any pending notification + ulTaskNotifyTake(pdTRUE, 0); + + TickType_t xLastWakeTime; + TickType_t elapsedTicks; + TickType_t delayTicks; + + // Define sensible upper bound for delay (ms) to avoid indefinite blocking due to bad callback + const int MAX_LOOP_DELAY_MS = 60 * 1000; // 60 seconds + + while (loop_active_flag) { + xLastWakeTime = xTaskGetTickCount(); + + int loopDelayMs = 0; + try { + loopDelayMs = callback(); // callback returns desired delay in milliseconds + } catch (const std::exception& e) { + ESP_LOGE("Animation_Loop", "Callback exception: %s", e.what()); + break; + } catch (...) { + ESP_LOGE("Animation_Loop", "Callback unknown exception"); + break; + } + + if (!loop_active_flag) break; + + // sanitize returned ms value and enforce minimum/maximum + if (loopDelayMs < (int)MinLoopDelay) loopDelayMs = MinLoopDelay; + if (loopDelayMs > MAX_LOOP_DELAY_MS) loopDelayMs = MAX_LOOP_DELAY_MS; + + // convert ms -> RTOS ticks (safe conversion) + TickType_t loopDelayTicks = pdMS_TO_TICKS(loopDelayMs); + + // compute elapsed ticks since callback start + elapsedTicks = xTaskGetTickCount() - xLastWakeTime; + + // compute remaining delay (in ticks) + delayTicks = (elapsedTicks < loopDelayTicks) ? (loopDelayTicks - elapsedTicks) : 0; + + if (delayTicks == 0) { + // Ensure we yield at least one tick to avoid busy-looping + vTaskDelay(1); + // Check if notified during the yield + if (ulTaskNotifyTake(pdTRUE, 0)) break; + } else { + // Wait for either a notification (termination) or the timeout + if (ulTaskNotifyTake(pdTRUE, delayTicks)) { + // notified => exit loop + break; + } + } + } + + loop_active_flag = false; +} // Animation Loop Template +/* void Animation_Loop_Duration(bool volatile& loop_active_flag, int speed, TickType_t durationMs, std::function callback) { loop_active_flag = true; speed = constrain(speed, 0, MaxSpeed); @@ -159,8 +281,72 @@ void Animation_Loop_Duration(bool volatile& loop_active_flag, int speed, TickTyp loop_active_flag = false; } +*/ + +void Animation_Loop_Duration(bool volatile& loop_active_flag, int speed, TickType_t durationMs, std::function callback) { + loop_active_flag = true; + speed = constrain(speed, 0, MaxSpeed); + + // treat durationMs as milliseconds (convert to ticks) + const TickType_t durationTicks = pdMS_TO_TICKS(durationMs); + + ulTaskNotifyTake(pdTRUE, 0); // Clear any pending notifications + TickType_t startTicks = xTaskGetTickCount(); + TickType_t xLastWakeTime; + + const int MAX_LOOP_DELAY_MS = 60 * 1000; // safety cap + while (loop_active_flag) { + xLastWakeTime = xTaskGetTickCount(); + + // Call animation function + int speedIncrease = 0; + try { + speedIncrease = callback(); + } catch (const std::exception& e) { + ESP_LOGE("Animation_Loop_Duration", "Callback exception: %s", e.what()); + break; + } catch (...) { + ESP_LOGE("Animation_Loop_Duration", "Callback unknown exception"); + break; + } + + if(!loop_active_flag) break; + + // Calculate combined speed with bounds protection + int totalSpeed = constrain(speed + speedIncrease, 0, MaxSpeed); + + // Calculate delay with minimum protection (ms) + int loopDelayMs = MaxSpeed - totalSpeed; + loopDelayMs = max(loopDelayMs, MinLoopDelay); + if (loopDelayMs > MAX_LOOP_DELAY_MS) loopDelayMs = MAX_LOOP_DELAY_MS; + TickType_t loopDelayTicks = pdMS_TO_TICKS(loopDelayMs); + + // Calculate remaining time with overflow protection + TickType_t elapsedTicks = xTaskGetTickCount() - xLastWakeTime; + TickType_t delayTicks = (elapsedTicks < loopDelayTicks) ? (loopDelayTicks - elapsedTicks) : 0; + + // Delay and Check for termination request + if (delayTicks == 0) { + vTaskDelay(1); + if (ulTaskNotifyTake(pdTRUE, 0)) break; + } else { + if (ulTaskNotifyTake(pdTRUE, delayTicks)) break; + } + + // Check if duration reached and wait for loop_active_flag + if (durationTicks > 0) { + TickType_t totalElapsed = xTaskGetTickCount() - startTicks; + if (totalElapsed >= durationTicks) { + break; // Auto-terminate when duration reached + } + } + } + + loop_active_flag = false; +} // Animation Loop Template +/* void Animation_Loop_Cycles(bool volatile& loop_active_flag, int speed, uint32_t loop_cycles, std::function callback) { loop_active_flag = true; uint32_t loop_cycle_count = 0; @@ -211,6 +397,66 @@ void Animation_Loop_Cycles(bool volatile& loop_active_flag, int speed, uint32_t loop_active_flag = false; } +*/ + +void Animation_Loop_Cycles(bool volatile& loop_active_flag, int speed, uint32_t loop_cycles, std::function callback) { + loop_active_flag = true; + uint32_t loop_cycle_count = 0; + speed = constrain(speed, 0, MaxSpeed); + + ulTaskNotifyTake(pdTRUE, 0); // Clear any pending notifications + TickType_t xLastWakeTime; + TickType_t elapsedTicks; + TickType_t delayTicks; + + const int MAX_LOOP_DELAY_MS = 60 * 1000; // safety cap + for(;;) { + xLastWakeTime = xTaskGetTickCount(); + + int speedIncrease = 0; + try { + speedIncrease = callback(); // Call animation function + } catch (const std::exception& e) { + ESP_LOGE("Animation_Loop_Cycles", "Callback exception: %s", e.what()); + break; + } catch (...) { + ESP_LOGE("Animation_Loop_Cycles", "Callback unknown exception"); + break; + } + + if(!loop_active_flag) break; + + // Calculate combined speed with bounds protection + int totalSpeed = constrain(speed + speedIncrease, 0, MaxSpeed); + + // Calculate delay with minimum protection (ms) + int loopDelayMs = MaxSpeed - totalSpeed; + loopDelayMs = max(loopDelayMs, MinLoopDelay); + if (loopDelayMs > MAX_LOOP_DELAY_MS) loopDelayMs = MAX_LOOP_DELAY_MS; + TickType_t loopDelayTicks = pdMS_TO_TICKS(loopDelayMs); + + // Calculate remaining time with overflow protection + elapsedTicks = xTaskGetTickCount() - xLastWakeTime; + delayTicks = (elapsedTicks < loopDelayTicks) ? (loopDelayTicks - elapsedTicks) : 0; + + // Delay and Check for termination request + if (delayTicks == 0) { + vTaskDelay(1); + if (ulTaskNotifyTake(pdTRUE, 0)) break; + } else { + if (ulTaskNotifyTake(pdTRUE, delayTicks)) break; + } + + // Check if cycles reached and exit + if (loop_cycle_count >= loop_cycles) { + break; + } + + loop_cycle_count++; + } + + loop_active_flag = false; +} /******************************************************************************** @@ -399,76 +645,6 @@ void Anim_Color_Sectors(bool volatile& activeFlag, CRGB* leds, int size, const C //#define COMET_FADE_FACTOR COMET_FADE_FACTOR2 #define MAX_COMETS 8 // Maximum number of comets supported /* -void Anim_Comets(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PACK& colorPack, int speed, bool randomDecay, bool shorterTail, int cometMultiplier = 1) { - // Validate inputs - int numComets = colorPack.size; - if (size <= 0 || numComets <= 0 || colorPack.size <= 0 || cometMultiplier <= 0) return; - - // Calculate comet size - int cometSize = (size / (numComets * cometMultiplier)) * COMET_SIZE_FACTOR; - if (cometSize < 1) cometSize = 1; - - // Set fade factor - uint8_t fadeFactor = shorterTail ? COMET_FADE_FACTOR2 : COMET_FADE_FACTOR1; - - // Initialize comet positions to be equally spaced - std::unique_ptr cometPositions(new (std::nothrow) int[numComets * cometMultiplier]); - if (!cometPositions) return; - int totalComets = numComets * cometMultiplier; - int spacing = size / totalComets; - for (int i = 0; i < totalComets; i++) { - cometPositions[i] = i * spacing; - } - - // Animation loop - bool direction = true; // true = forward, false = backward - int loopCounter = 0; - try { - const int loopTick = 30; // ms per animation tick - Animation_Loop(activeFlag, loopTick, [&]() -> int { - // Fade all LEDs - for (int i = 0; i < size; i++) { - if(!randomDecay) { - leds[i].fadeToBlackBy(fadeFactor); - } else if(random(10) > 5){ - leds[i].fadeToBlackBy(fadeFactor); - } - } - - // Move and draw comets - for (int i = 0; i < totalComets; i++) { - if (direction) { - cometPositions[i] = (cometPositions[i] + 1) % size; - } else { - cometPositions[i] = (cometPositions[i] - 1 + size) % size; - } - - // Draw comet with solid color - CRGB color = colorPack.col[i % colorPack.size]; - for (int j = 0; j < cometSize; j++) { - int pos = (cometPositions[i] - j + size) % size; - leds[pos] += color; - } - } - - loopCounter++; - if(loopCounter >= (size * CYCLES_PER_DIRECTION)){ - direction = !direction; - loopCounter = 0; - } - - FastLED.show(); - return 0; - }); - } catch (const std::exception& e) { - ESP_LOGE("Anim_Comets", "Exception in Animation_Loop: %s", e.what()); - } catch (...) { - ESP_LOGE("Anim_Comets", "Unknown exception in Animation_Loop"); - } - // No need to delete cometPositions as it is managed by std::unique_ptr -} -*/ - void Anim_Comets(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PACK& colorPack, int minSpeed, int maxSpeed, bool randomDecay, int cometMultiplier) { // Validate inputs int numComets = colorPack.size; @@ -479,8 +655,8 @@ void Anim_Comets(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PA return; } - // Calculate comet size - int cometSize = (size / totalComets) * COMET_SIZE_FACTOR; + // Calculate comet size (use float math and round to avoid integer-division truncation) + int cometSize = (int)(((float)size * (float)COMET_SIZE_FACTOR) / (float)totalComets + 0.5f); if (cometSize < 1) cometSize = 1; // Set fade factor @@ -500,9 +676,14 @@ void Anim_Comets(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PA int pos; CRGB color; int speed = minSpeed; - int loopDuration = (size * CYCLES_PER_DIRECTION); + int loopDuration = size * CYCLES_PER_DIRECTION; + // Defensive: ensure loopDuration isn't zero to avoid divide-by-zero later + if (loopDuration < 1) loopDuration = 1; int thirdLoop = loopDuration / 3; - int twoThirdLoop = (2 * loopDuration) / 3; + // Defensive: ensure thirdLoop is at least 1 for progress calculations + if (thirdLoop < 1) thirdLoop = 1; + // Keep twoThirdLoop consistent with thirdLoop to avoid rounding surprises + int twoThirdLoop = 2 * thirdLoop; try { Animation_Loop_Variable(activeFlag, [&]() -> int { // Fade all LEDs @@ -558,7 +739,11 @@ void Anim_Comets(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PA FastLED.show(); - return max(MaxSpeed - speed, MinLoopDelay); + // Compute delay to return to Animation_Loop_Variable. + // Ensure we never return a value less than MinLoopDelay. + int computed = MaxSpeed - speed; + if (computed < MinLoopDelay) computed = MinLoopDelay; + return computed; }); fill_solid(leds, size, CRGB::Black); @@ -569,6 +754,131 @@ void Anim_Comets(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PA ESP_LOGE("Anim_Comets", "Unknown exception in Animation_Loop"); } } +*/ +void Anim_Comets(bool volatile& activeFlag, CRGB* leds, int size, const COLOR_PACK& colorPack, int minSpeed, int maxSpeed, bool randomDecay, int cometMultiplier) { + // Validate inputs + int numComets = colorPack.size; + int totalComets = numComets * cometMultiplier; + + if (size <= 0 || numComets <= 0 || colorPack.size <= 0 || cometMultiplier <= 0 || totalComets > MAX_COMETS) { + ESP_LOGE("Anim_Comets", "Invalid input parameters or too many comets (max: %d, requested: %d)", MAX_COMETS, totalComets); + return; + } + + // Sanitize speed inputs to known bounds + minSpeed = constrain(minSpeed, 0, MaxSpeed); + maxSpeed = constrain(maxSpeed, 0, MaxSpeed); + if (minSpeed > maxSpeed) { int t=minSpeed; minSpeed=maxSpeed; maxSpeed=t; } + + // Calculate comet size (use float math and round to avoid integer-division truncation) + int cometSize = (int)(((float)size * (float)COMET_SIZE_FACTOR) / (float)totalComets + 0.5f); + if (cometSize < 1) cometSize = 1; + + // Set fade factor + uint8_t fadeFactor = map(totalComets, 1, MAX_COMETS, COMET_FADE_FACTOR1, COMET_FADE_FACTOR2); + fadeFactor = constrain(fadeFactor, COMET_FADE_FACTOR1, COMET_FADE_FACTOR2); + + // Initialize comet positions with fixed array, evenly distributed + int cometPositions[MAX_COMETS] = {0}; + for (int i = 0; i < totalComets; i++) { + // Even distribution even when size not divisible by totalComets + cometPositions[i] = (i * size) / totalComets; + } + + // Animation loop + bool direction = true; // true = forward, false = backward + int loopCounter = 0; + int pos; + CRGB color; + int speed = minSpeed; + + // Cache size/limits locally for speed + const int localSize = size; + const int localTotalComets = totalComets; + int loopDuration = localSize * CYCLES_PER_DIRECTION; + // Defensive: ensure loopDuration isn't zero to avoid divide-by-zero later + if (loopDuration < 1) loopDuration = 1; + int thirdLoop = loopDuration / 3; + if (thirdLoop < 1) thirdLoop = 1; + int twoThirdLoop = 2 * thirdLoop; + + try { + Animation_Loop_Variable(activeFlag, [&]() -> int { + // Fade all LEDs (keep this O(N) operation but keep it tight) + for (int i = 0; i < localSize; i++) { + if (!randomDecay) { + leds[i].fadeToBlackBy(fadeFactor); + } else if (getRandomValue(10) > 5) { + leds[i].fadeToBlackBy(fadeFactor); + } + } + + // Move and draw comets + for (int i = 0; i < localTotalComets; i++) { + if (direction) { + cometPositions[i] = (cometPositions[i] + 1) % localSize; + } else { + cometPositions[i] = (cometPositions[i] - 1 + localSize) % localSize; + } + + // Draw comet with solid color (safe modulo) + color = colorPack.col[i % colorPack.size]; + for (int j = 0; j < cometSize; j++) { + // Tail follows the direction of movement + pos = direction ? (cometPositions[i] - j) : (cometPositions[i] + j); + pos = (pos % localSize + localSize) % localSize; // safe modulus + leds[pos] += color; + } + } + + // Speed ramping: 1/3 aggressive ramp up, 1/3 constant, 1/3 aggressive ramp down + if (loopCounter < thirdLoop) { + // First third: ease-out quartic implemented without pow() + float progress = (float)loopCounter / (float)thirdLoop; // 0.0 to 1.0 + float oneMinus = 1.0f - progress; + float eased = 1.0f - (oneMinus * oneMinus * oneMinus * oneMinus); // 1 - (1-t)^4 + speed = minSpeed + (int)((maxSpeed - minSpeed) * eased); + } + else if (loopCounter < twoThirdLoop) { + // Middle third: constant at maxSpeed + speed = maxSpeed; + } + else { + // Last third: ease-in quartic implemented without pow() + float progress = (float)(loopCounter - twoThirdLoop) / (float)thirdLoop; // 0.0 to 1.0 + if (progress < 0.0f) progress = 0.0f; if (progress > 1.0f) progress = 1.0f; + float eased = (progress * progress * progress * progress); // t^4 + speed = maxSpeed - (int)((maxSpeed - minSpeed) * eased); + } + + if (++loopCounter >= loopDuration) { + direction = !direction; + loopCounter = 0; + speed = minSpeed; + } + + FastLED.show(); + + // Compute delay to return to Animation_Loop_Variable. + // Ensure we never return a value less than MinLoopDelay. + int computed = MaxSpeed - speed; + if (computed < MinLoopDelay) computed = MinLoopDelay; + return computed; + }); + + fill_solid(leds, size, CRGB::Black); + + } catch (const std::exception& e) { + ESP_LOGE("Anim_Comets", "Exception in Animation_Loop: %s", e.what()); + } catch (...) { + ESP_LOGE("Anim_Comets", "Unknown exception in Animation_Loop"); + } + + // NOTE: For production/stability consider: + // - Replacing volatile activeFlag with std::atomic or task-notify mechanism. + // - If FastLED.show() blocks too long for very long strips consider chunked updates or an alternate driver. + // - If pow() usage was widespread, replace with fixed-point or inline multiplies as done above. +} void Anim_TimedFill(bool volatile& activeFlag, CRGB* leds, int size, CRGB baseCol, CRGB fillCol, int totalDurationMs, int shift = 0) @@ -698,6 +1008,8 @@ void Anim_TimedFill_Flash(bool volatile& activeFlag, CRGB* leds, int size, PWM_O if (flashElapsed >= flashTimeout) { // Flash timeout expired, set PWM to minimum pwmOut->setOutput(pwmMin); + // exit the loop + activeFlag = false; ESP_LOGI("Anim_TimedFill_Flash", "Flash timeout expired, PWM set to minimum"); } // Continue in infinite loop regardless of timeout status @@ -754,9 +1066,8 @@ void Anim_SolidWhite(bool volatile& activeFlag, CRGB* leds, PWM_Output* pwmOut, // No animation, just maintain the solid white state return 0; }); - if(pwmOut){ - pwmOut->setOutput(0); // Turn off PWM output - } + + if(pwmOut){ pwmOut->setOutput(0); }// Turn off PWM output FastLED.setBrightness(origBright); // Restore original brightness } diff --git a/src/AppUpgrade.cpp b/src/AppUpgrade.cpp index c6b6f28..ba10eac 100644 --- a/src/AppUpgrade.cpp +++ b/src/AppUpgrade.cpp @@ -32,6 +32,7 @@ AppUpdater::AppUpdater(fs::FS& fs, Version localVersion, const char* bucket, con if (buffer_size < 1024) buffer_size = 1024; // Absolute minimum is 1KB downloadBuffer.reset(new uint8_t[buffer_size]); + downloadBufferSize = buffer_size; baseUrl = bucket ? String(bucket) : String(DEFAULT_MANIFEST_URL); // Ensure baseUrl ends with a single '/' @@ -81,6 +82,7 @@ AppUpdater::ManifestCheckResult AppUpdater::checkManifest() { http.end(); if(attempt+1 < HTTP_RETRY_COUNT) vTaskDelay(pdMS_TO_TICKS(HTTP_RETRY_DELAY_MS)); } + if(payload.isEmpty()){ ESP_LOGE(TAG, "Failed to fetch manifest after retries"); return ManifestCheckResult::ERROR_FETCH_FAILED; @@ -159,6 +161,7 @@ bool AppUpdater::updateFile(const char* remotePath, const char* localPath, const } else { ESP_LOGI(TAG, "Local file does not exist: %s", localPath); } + if(skip){ ESP_LOGI(TAG, "File already up to date: %s", localPath); updateProgress(UpdateStatus::FILE_SKIPPED, 100, localPath); @@ -179,9 +182,12 @@ bool AppUpdater::updateFile(const char* remotePath, const char* localPath, const http.end(); if(attempt+1 < HTTP_RETRY_COUNT) vTaskDelay(pdMS_TO_TICKS(HTTP_RETRY_DELAY_MS)); } + if (httpCode != HTTP_CODE_OK) { ESP_LOGE(TAG, "Download failed for %s: HTTP code %d", localPath, httpCode); - updateProgress(UpdateStatus::ERROR, 0, String(String("Download failed: ") + localPath).c_str()); + char buf[128]; + snprintf(buf, sizeof(buf), "Download failed: %s", localPath); + updateProgress(UpdateStatus::ERROR, 0, buf); http.end(); return false; } @@ -215,33 +221,36 @@ bool AppUpdater::updateFile(const char* remotePath, const char* localPath, const bool AppUpdater::verifyAndSaveFile(WiFiClient* stream, size_t contentLength, const char* localPath, const char* remotePath, const char* expectedMd5) { const int MAX_RETRIES = 2; // Maximum number of retries for MD5 failure - + for (int retry = 0; retry <= MAX_RETRIES; retry++) { + HTTPClient retryHttp; // kept alive for the duration of this iteration if used + WiFiClient* activeStream = stream; + size_t activeContentLength = contentLength; + if (retry > 0) { ESP_LOGW(TAG, "Retrying download of %s (attempt %d/%d)", localPath, retry, MAX_RETRIES); // Need to re-fetch the file for retry - use the REMOTE path, not local path String url = buildUrl(remotePath); - HTTPClient http; - http.begin(url); - int httpCode = http.GET(); + retryHttp.begin(url); + int httpCode = retryHttp.GET(); if (httpCode != HTTP_CODE_OK) { ESP_LOGE(TAG, "Retry download failed: %d", httpCode); - http.end(); + retryHttp.end(); continue; // Try next retry if available } - stream = http.getStreamPtr(); - contentLength = http.getSize(); + activeStream = retryHttp.getStreamPtr(); + activeContentLength = retryHttp.getSize(); } - + MD5Builder md5; md5.begin(); size_t totalRead = 0; - + // Create temporary filename in the same directory as the target file String targetDir = String(localPath); int lastSlash = targetDir.lastIndexOf('/'); String tempPath; - + if (lastSlash >= 0) { // Extract directory and filename String directory = targetDir.substring(0, lastSlash + 1); @@ -251,62 +260,84 @@ bool AppUpdater::verifyAndSaveFile(WiFiClient* stream, size_t contentLength, con // File is in root directory tempPath = "/temp_" + String(localPath) + ".download"; } - + // Clean up any existing temp file first if (fileSystem.exists(tempPath.c_str())) { ESP_LOGW(TAG, "Removing existing temp file: %s", tempPath.c_str()); fileSystem.remove(tempPath.c_str()); } - + ESP_LOGI(TAG, "Using temp file path: %s for target: %s", tempPath.c_str(), localPath); - + ESP_LOGI(TAG, "verifyAndSaveFile: downloadBufferSize=%u", (unsigned)downloadBufferSize); + + // Check available space if content length is known + if (activeContentLength > 0) { + size_t freeBytes = LittleFS.totalBytes() - LittleFS.usedBytes(); + // Leave a small headroom (5%) to avoid filling filesystem completely + if (activeContentLength > freeBytes * 95 / 100) { + ESP_LOGE(TAG, "Not enough LittleFS space for %s (%u bytes needed, %u bytes free)", + localPath, (unsigned)activeContentLength, (unsigned)freeBytes); + if (retry > 0) retryHttp.end(); + continue; + } + } + // Open temporary file for writing (LittleFS will create directories automatically) File file = fileSystem.open(tempPath.c_str(), FILE_WRITE, true); // true = create if not exists if (!file) { ESP_LOGE(TAG, "Failed to open temporary file for writing: %s", tempPath.c_str()); - + // Try to diagnose the issue - ESP_LOGE(TAG, "LittleFS info - Used: %u bytes, Total: %u bytes", - LittleFS.usedBytes(), LittleFS.totalBytes()); - + ESP_LOGE(TAG, "LittleFS info - Used: %u bytes, Total: %u bytes", + (unsigned)LittleFS.usedBytes(), (unsigned)LittleFS.totalBytes()); + // Check if we're out of space if (LittleFS.usedBytes() >= LittleFS.totalBytes() * 0.95) { ESP_LOGE(TAG, "LittleFS nearly full - may not have space for temp file"); } - + + if (retry > 0) retryHttp.end(); return false; } - - //updateProgress(UpdateStatus::DOWNLOADING, 0, localPath); - - if (contentLength > 0) { + + // Defensive: ensure download buffer exists + if (!downloadBuffer || downloadBufferSize == 0) { + ESP_LOGE(TAG, "No download buffer available"); + file.close(); + fileSystem.remove(tempPath.c_str()); + if (retry > 0) retryHttp.end(); + return false; + } + + if (activeContentLength > 0) { // Single pass with known content length - while (totalRead < contentLength) { - if(g_UpdateCancelFlag){ file.close(); fileSystem.remove(tempPath.c_str()); return false; } - size_t available = stream->available(); + while (totalRead < activeContentLength) { + if(g_UpdateCancelFlag){ file.close(); fileSystem.remove(tempPath.c_str()); if (retry > 0) retryHttp.end(); return false; } + size_t available = activeStream->available(); if (available) { - size_t readLen = stream->readBytes(downloadBuffer.get(), std::min(available, size_t(BUFFER_SIZE))); - + size_t readLen = activeStream->readBytes(downloadBuffer.get(), std::min(available, downloadBufferSize)); + // Write to temp file and update MD5 if (file.write(downloadBuffer.get(), readLen) != readLen) { ESP_LOGE(TAG, "Failed to write to temporary file"); - + file.close(); fileSystem.remove(tempPath.c_str()); + if (retry > 0) retryHttp.end(); return false; } - + md5.add(downloadBuffer.get(), readLen); totalRead += readLen; - updateProgress(UpdateStatus::DOWNLOADING, (totalRead * 80) / contentLength , localPath); + updateProgress(UpdateStatus::DOWNLOADING, (totalRead * 80) / activeContentLength , localPath); } yield(); } } else { // Unknown content length: read until stream ends for (;;) { - if(g_UpdateCancelFlag){ file.close(); fileSystem.remove(tempPath.c_str()); return false; } - size_t readLen = stream->readBytes(downloadBuffer.get(), BUFFER_SIZE); + if(g_UpdateCancelFlag){ file.close(); fileSystem.remove(tempPath.c_str()); if (retry > 0) retryHttp.end(); return false; } + size_t readLen = activeStream->readBytes(downloadBuffer.get(), downloadBufferSize); if (readLen == 0) { break; } @@ -314,6 +345,7 @@ bool AppUpdater::verifyAndSaveFile(WiFiClient* stream, size_t contentLength, con ESP_LOGE(TAG, "Failed to write to temporary file"); file.close(); fileSystem.remove(tempPath.c_str()); + if (retry > 0) retryHttp.end(); return false; } md5.add(downloadBuffer.get(), readLen); @@ -326,44 +358,45 @@ bool AppUpdater::verifyAndSaveFile(WiFiClient* stream, size_t contentLength, con yield(); } } - + file.close(); md5.calculate(); String calculatedMd5 = md5.toString(); - + // Verify MD5 hash updateProgress(UpdateStatus::VERIFYING, 90, localPath); - - ESP_LOGI(TAG, "MD5 verification for %s: Expected='%s', Calculated='%s'", + + ESP_LOGI(TAG, "MD5 verification for %s: Expected='%s', Calculated='%s'", localPath, expectedMd5, calculatedMd5.c_str()); - + // Compare MD5 case-insensitively (in case there are case differences) String expectedMd5Lower = String(expectedMd5); expectedMd5Lower.toLowerCase(); String calculatedMd5Lower = calculatedMd5; calculatedMd5Lower.toLowerCase(); - + if (!calculatedMd5Lower.equals(expectedMd5Lower)) { - ESP_LOGE(TAG, "MD5 mismatch for %s (attempt %d/%d). Expected: %s, Got: %s", + ESP_LOGE(TAG, "MD5 mismatch for %s (attempt %d/%d). Expected: %s, Got: %s", localPath, retry+1, MAX_RETRIES+1, expectedMd5, calculatedMd5.c_str()); - ESP_LOGE(TAG, "Length comparison - Expected: %d chars, Got: %d chars", - strlen(expectedMd5), calculatedMd5.length()); + ESP_LOGE(TAG, "Length comparison - Expected: %d chars, Got: %d chars", + (int)strlen(expectedMd5), (int)calculatedMd5.length()); fileSystem.remove(tempPath.c_str()); - + if (retry < MAX_RETRIES) { // Will retry in next loop iteration + if (retry > 0) retryHttp.end(); continue; } - + // Special case for certain file types - allow them to be used even with MD5 mismatch // This is a fallback option for non-critical files like HTML pages bool isNonCriticalFile = false; - if (String(localPath).endsWith(".html") || - String(localPath).endsWith(".css") || + if (String(localPath).endsWith(".html") || + String(localPath).endsWith(".css") || String(localPath).endsWith(".js")) { isNonCriticalFile = true; } - + if (isNonCriticalFile) { ESP_LOGW(TAG, "Using file %s despite MD5 mismatch (non-critical file)", localPath); // We'll still keep this file but report it as a verification failure @@ -383,26 +416,29 @@ bool AppUpdater::verifyAndSaveFile(WiFiClient* stream, size_t contentLength, con } } } - + // Rename the temp file to the final location if (fileSystem.exists(localPath)) { fileSystem.remove(localPath); } if (!fileSystem.rename(tempPath.c_str(), localPath)) { - ESP_LOGE(TAG, "Failed to rename temporary file for non-critical use: %s -> %s", + ESP_LOGE(TAG, "Failed to rename temporary file for non-critical use: %s -> %s", tempPath.c_str(), localPath); fileSystem.remove(tempPath.c_str()); + if (retry > 0) retryHttp.end(); return false; } + if (retry > 0) retryHttp.end(); // Return false to indicate verification failure, but the file will still be used return false; } - + + if (retry > 0) retryHttp.end(); return false; } - + updateProgress(UpdateStatus::VERIFYING, 95, localPath); - + // Ensure target directory exists before rename String dirPath = String(localPath); int targetLastSlash = dirPath.lastIndexOf('/'); @@ -419,7 +455,7 @@ bool AppUpdater::verifyAndSaveFile(WiFiClient* stream, size_t contentLength, con } } } - + // Replace original file with verified temp file if (fileSystem.exists(localPath)) { fileSystem.remove(localPath); @@ -427,13 +463,15 @@ bool AppUpdater::verifyAndSaveFile(WiFiClient* stream, size_t contentLength, con if (!fileSystem.rename(tempPath.c_str(), localPath)) { ESP_LOGE(TAG, "Failed to rename temporary file: %s -> %s", tempPath.c_str(), localPath); fileSystem.remove(tempPath.c_str()); + if (retry > 0) retryHttp.end(); return false; } - + updateProgress(UpdateStatus::VERIFYING, 100, localPath); + if (retry > 0) retryHttp.end(); return true; } - + return false; // All retries failed } @@ -450,7 +488,7 @@ String AppUpdater::getLocalMD5(const char* filePath){ size_t totalRead = 0; size_t readLen = 0; while (totalRead < fileSize) { - readLen = file.readBytes(reinterpret_cast(downloadBuffer.get()), std::min(fileSize - totalRead, size_t(BUFFER_SIZE))); + readLen = file.readBytes(reinterpret_cast(downloadBuffer.get()), std::min(fileSize - totalRead, downloadBufferSize)); md5Builder.add(downloadBuffer.get(), readLen); totalRead += readLen; } @@ -569,6 +607,7 @@ bool AppUpdater::updateApp() { if (httpCode != HTTP_CODE_OK) { ESP_LOGE(TAG, "Firmware download failed: %d", httpCode); updateProgress(UpdateStatus::ERROR, 0, "Firmware: Firmware download failed"); + http.end(); return false; } @@ -662,12 +701,12 @@ bool AppUpdater::updateApp() { while (remaining > 0 && failedReads < MAX_FAILED_READS) { // Check for cancellation - if(g_UpdateCancelFlag) { - ESP_LOGE(TAG, "Update cancelled by user"); - Update.abort(); - http.end(); - return false; - } + if(g_UpdateCancelFlag) { + ESP_LOGE(TAG, "Update cancelled by user"); + Update.abort(); + http.end(); + return false; + } // Check WiFi status every 5 seconds if (millis() - lastWatchdogKick > 5000) { @@ -735,8 +774,9 @@ bool AppUpdater::updateApp() { // Send periodic progress updates to keep client informed if (millis() - lastWatchdogKick > 5000) { int percent = (totalReceived * 100) / firmwareSize; - updateProgress(UpdateStatus::DOWNLOADING, percent, - String("Firmware: " + String(percent) + "% - waiting for data...").c_str()); + char buf[64]; + snprintf(buf, sizeof(buf), "Firmware: %d%% - waiting for data...", percent); + updateProgress(UpdateStatus::DOWNLOADING, percent, buf); } delay(100); // Short delay to prevent CPU hogging @@ -782,8 +822,9 @@ bool AppUpdater::updateApp() { lastProgressTime = millis(); // Just update with received byte count since we don't know total - updateProgress(UpdateStatus::DOWNLOADING, 0, - String("Firmware: " + String(totalReceived / 1024) + "KB received").c_str()); + char buf2[64]; + snprintf(buf2, sizeof(buf2), "Firmware: %uKB received", (unsigned)(totalReceived / 1024)); + updateProgress(UpdateStatus::DOWNLOADING, 0, buf2); } else { emptyReads++; delay(100); @@ -878,115 +919,122 @@ void firmwareUpdateTask(void* parameter) { esp_task_wdt_init(60, true); // 60 second timeout, panic on timeout esp_task_wdt_add(NULL); // Add current task to watchdog - try { - loadUpdateJson(); - - esp_task_wdt_reset(); // Reset watchdog timer after JSON loading - - // Initialize updater with smart pointer - std::unique_ptr updater(new AppUpdater( - LittleFS, localVersion, updateUrl.c_str(), "manifest.json", "firmware.bin")); - updater->setProgressCallback(updateProgress); - - ESP_LOGI(TAG, "Starting update check from: %s", updateUrl.c_str()); - - // Check and perform updates - auto manifestResult = updater->checkManifest(); - - if (manifestResult != AppUpdater::ManifestCheckResult::UPDATE_AVAILABLE) { - // Handle different error cases - std::string errorMsg; - switch (manifestResult) { - case AppUpdater::ManifestCheckResult::ERROR_FETCH_FAILED: - errorMsg = "Failed to fetch manifest"; - break; - case AppUpdater::ManifestCheckResult::ERROR_TOO_LARGE: - errorMsg = "Manifest file too large"; - break; - case AppUpdater::ManifestCheckResult::ERROR_PARSE_FAILED: - errorMsg = "Failed to parse manifest"; - break; - case AppUpdater::ManifestCheckResult::ERROR_NO_FILES_SECTION: - errorMsg = "Manifest missing files section"; - break; - case AppUpdater::ManifestCheckResult::ERROR_NO_VERSION: - errorMsg = "Manifest missing version section"; - break; - case AppUpdater::ManifestCheckResult::VERSION_CURRENT: - errorMsg = "Current version is up to date"; - // This is not actually an error - ESP_LOGI(TAG, "No update needed: %s", errorMsg.c_str()); - updateProgress(AppUpdater::UpdateStatus::MESSAGE, 0, errorMsg.c_str()); - // Don't throw, just exit gracefully - break; - default: - errorMsg = "Unknown manifest check error"; - } - - if (manifestResult != AppUpdater::ManifestCheckResult::VERSION_CURRENT) { - ESP_LOGE(TAG, "Manifest check failed: %s", errorMsg.c_str()); - updateProgress(AppUpdater::UpdateStatus::ERROR, 0, errorMsg.c_str()); - } - } - - if (updater->IsUpdateAvailable()) { - bool filesUpdated = true; - bool firmwareUpdated = false; // Initialize to false - only set to true if firmware is actually updated - - // Update files based on update mode - if (g_UpdateMode == UpdateMode::UPDATE_FILES_ONLY || g_UpdateMode == UpdateMode::UPDATE_BOTH) { - ESP_LOGI(TAG, "Update mode includes files, updating files..."); - filesUpdated = updater->updateFilesArray(); - if (!filesUpdated) { - ESP_LOGW(TAG, "Some files failed to update"); - if (g_UpdateMode == UpdateMode::UPDATE_FILES_ONLY) { - ESP_LOGE(TAG, "Files-only update failed"); - updateProgress(AppUpdater::UpdateStatus::ERROR, 0, "Failed to update files"); - // Skip to cleanup since this is files-only mode and it failed - goto cleanup; - } else { - ESP_LOGW(TAG, "File update failed, but continuing with firmware update"); - } - } - } else { - ESP_LOGI(TAG, "Skipping file updates (mode: firmware only)"); - } - - // Update firmware based on update mode - if (g_UpdateMode == UpdateMode::UPDATE_FIRMWARE_ONLY || g_UpdateMode == UpdateMode::UPDATE_BOTH) { - ESP_LOGI(TAG, "Update mode includes firmware, updating firmware..."); - firmwareUpdated = updater->updateApp(); - if (!firmwareUpdated) { - ESP_LOGE(TAG, "Failed to update firmware"); - updateProgress(AppUpdater::UpdateStatus::ERROR, 0, "Failed to update firmware"); - // Skip to cleanup since firmware update failed - goto cleanup; - } - } else { - ESP_LOGI(TAG, "Skipping firmware update (mode: files only)"); - } - - // Determine if we need to restart - bool needsRestart = (g_UpdateMode == UpdateMode::UPDATE_FIRMWARE_ONLY || g_UpdateMode == UpdateMode::UPDATE_BOTH) && firmwareUpdated; - - if (needsRestart) { - ESP_LOGI(TAG, "Firmware update successful, restarting..."); - sendUpdateMessage("Restarting... ", true, 100); - vTaskDelay(2000); - ESP.restart(); - } else { - ESP_LOGI(TAG, "Update completed successfully (no restart required)"); - updateProgress(AppUpdater::UpdateStatus::COMPLETE, 100, "Update completed successfully"); - } - } - - } catch (const std::exception& e) { - ESP_LOGE(TAG, "Update failed with exception: %s", e.what()); - updateProgress(AppUpdater::UpdateStatus::ERROR, 0, e.what()); - } catch (...) { - ESP_LOGE(TAG, "Update failed with unknown exception"); - updateProgress(AppUpdater::UpdateStatus::ERROR, 0, "Unknown error during update"); + // Load update.json; proceed only if successful + if (!loadUpdateJson()) { + ESP_LOGE(TAG, "Failed to load update.json, aborting update task"); + // Clean up watchdog and exit task + esp_task_wdt_delete(NULL); + Update_Task_Handle = NULL; + vTaskDelete(NULL); + return; } + + esp_task_wdt_reset(); // Reset watchdog timer after JSON loading + + // Initialize updater with smart pointer + std::unique_ptr updater(new AppUpdater( + LittleFS, localVersion, updateUrl.c_str(), "manifest.json", "firmware.bin")); + updater->setProgressCallback(updateProgress); + + ESP_LOGI(TAG, "Starting update check from: %s", updateUrl.c_str()); + + // Check and perform updates + auto manifestResult = updater->checkManifest(); + + if (manifestResult != AppUpdater::ManifestCheckResult::UPDATE_AVAILABLE) { + // Handle different error cases + std::string errorMsg; + switch (manifestResult) { + case AppUpdater::ManifestCheckResult::ERROR_FETCH_FAILED: + errorMsg = "Failed to fetch manifest"; + break; + case AppUpdater::ManifestCheckResult::ERROR_TOO_LARGE: + errorMsg = "Manifest file too large"; + break; + case AppUpdater::ManifestCheckResult::ERROR_PARSE_FAILED: + errorMsg = "Failed to parse manifest"; + break; + case AppUpdater::ManifestCheckResult::ERROR_NO_FILES_SECTION: + errorMsg = "Manifest missing files section"; + break; + case AppUpdater::ManifestCheckResult::ERROR_NO_VERSION: + errorMsg = "Manifest missing version section"; + break; + case AppUpdater::ManifestCheckResult::VERSION_CURRENT: + errorMsg = "Current version is up to date"; + // This is not actually an error + ESP_LOGI(TAG, "No update needed: %s", errorMsg.c_str()); + updateProgress(AppUpdater::UpdateStatus::MESSAGE, 0, errorMsg.c_str()); + // Don't throw, just exit gracefully + break; + default: + errorMsg = "Unknown manifest check error"; + } + + if (manifestResult != AppUpdater::ManifestCheckResult::VERSION_CURRENT) { + ESP_LOGE(TAG, "Manifest check failed: %s", errorMsg.c_str()); + updateProgress(AppUpdater::UpdateStatus::ERROR, 0, errorMsg.c_str()); + } + } + + if (updater->IsUpdateAvailable()) { + bool filesUpdated = true; + bool firmwareUpdated = false; // Initialize to false - only set to true if firmware is actually updated + + // Update files based on update mode + if (g_UpdateMode == UpdateMode::UPDATE_FILES_ONLY || g_UpdateMode == UpdateMode::UPDATE_BOTH) { + ESP_LOGI(TAG, "Update mode includes files, updating files..."); + filesUpdated = updater->updateFilesArray(); + if (!filesUpdated) { + ESP_LOGW(TAG, "Some files failed to update"); + if (g_UpdateMode == UpdateMode::UPDATE_FILES_ONLY) { + ESP_LOGE(TAG, "Files-only update failed"); + updateProgress(AppUpdater::UpdateStatus::ERROR, 0, "Failed to update files"); + // Clean up and exit task + esp_task_wdt_delete(NULL); + Update_Task_Handle = NULL; + vTaskDelete(NULL); + return; + } else { + ESP_LOGW(TAG, "File update failed, but continuing with firmware update"); + } + } + } else { + ESP_LOGI(TAG, "Skipping file updates (mode: firmware only)"); + } + + // Update firmware based on update mode + if (g_UpdateMode == UpdateMode::UPDATE_FIRMWARE_ONLY || g_UpdateMode == UpdateMode::UPDATE_BOTH) { + ESP_LOGI(TAG, "Update mode includes firmware, updating firmware..."); + firmwareUpdated = updater->updateApp(); + if (!firmwareUpdated) { + ESP_LOGE(TAG, "Failed to update firmware"); + updateProgress(AppUpdater::UpdateStatus::ERROR, 0, "Failed to update firmware"); + // Clean up and exit task + esp_task_wdt_delete(NULL); + Update_Task_Handle = NULL; + vTaskDelete(NULL); + return; + } + } else { + ESP_LOGI(TAG, "Skipping firmware update (mode: files only)"); + } + + // Determine if we need to restart + bool needsRestart = (g_UpdateMode == UpdateMode::UPDATE_FIRMWARE_ONLY || g_UpdateMode == UpdateMode::UPDATE_BOTH) && firmwareUpdated; + + if (needsRestart) { + ESP_LOGI(TAG, "Firmware update successful, restarting..."); + sendUpdateMessage("Restarting... ", true, 100); + vTaskDelay(2000); + ESP.restart(); + } else { + ESP_LOGI(TAG, "Update completed successfully (no restart required)"); + updateProgress(AppUpdater::UpdateStatus::COMPLETE, 100, "Update completed successfully"); + } + } + + // No C++ exceptions used - errors are handled inline and via return codes cleanup: // Clean up watchdog before exit @@ -1007,7 +1055,12 @@ void startVersionCheckTask() { void versionCheckTask(void* parameter){ if(updateUrl == ""){ - loadUpdateJson(); + if(!loadUpdateJson()){ + ESP_LOGE(TAG, "versionCheckTask: failed to load update.json"); + versionCheckTask_Handle = NULL; + vTaskDelete(NULL); + return; + } } AppUpdater updater(LittleFS, localVersion, updateUrl.c_str(), "manifest.json", "firmware.bin"); @@ -1025,35 +1078,36 @@ void versionCheckTask(void* parameter){ vTaskDelete(NULL); } -void loadUpdateJson(void) { - try { - ESP_LOGD(TAG, "loadUpdateJaon function..."); - if(updateUrl == "") { - String updateJsonPath = "/system/update.json"; +bool loadUpdateJson(void) { + ESP_LOGD(TAG, "loadUpdateJson function..."); + if(updateUrl == "") { + String updateJsonPath = "/system/update.json"; - // Read and parse update.json - File file = LittleFS.open(updateJsonPath); - if (!file) { - throw std::runtime_error("Failed to open update.json"); - } - - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - - if (error) { throw std::runtime_error("Failed to parse update.json"); } - - // Get update configuration - JsonObject jObj = doc.as(); - String folderName = jsonConstrainString(TAG, jObj, "folder", "latest/"); - String baseUrl = jsonConstrainString(TAG, jObj, "baseurl", "https://s3-minio.boothwizard.com/boothifier/"); - updateUrl = baseUrl + folderName; - - ESP_LOGD(TAG, "updateUrl: %s", updateUrl.c_str()); + // Read and parse update.json + File file = LittleFS.open(updateJsonPath); + if (!file) { + ESP_LOGE(TAG, "Failed to open update.json"); + return false; } - } catch (const std::exception& e) { - ESP_LOGE(TAG, "Update failed: %s", e.what()); + + JsonDocument doc; + DeserializationError error = deserializeJson(doc, file); + file.close(); + + if (error) { + ESP_LOGE(TAG, "Failed to parse update.json: %s", error.c_str()); + return false; + } + + // Get update configuration + JsonObject jObj = doc.as(); + String folderName = jsonConstrainString(TAG, jObj, "folder", "latest/"); + String baseUrl = jsonConstrainString(TAG, jObj, "baseurl", "https://s3-minio.boothwizard.com/boothifier/"); + updateUrl = baseUrl + folderName; + + ESP_LOGD(TAG, "updateUrl: %s", updateUrl.c_str()); } + return true; } void updateProgress(AppUpdater::UpdateStatus newStatus, int percentage, const char* message = nullptr) { diff --git a/src/BLE_SP110E.cpp b/src/BLE_SP110E.cpp index 15ed1b0..f6d5b04 100644 --- a/src/BLE_SP110E.cpp +++ b/src/BLE_SP110E.cpp @@ -5,6 +5,9 @@ #include "ATALights.h" #include "BleSettings.h" #include +#include "my_device.h" +#include "global.h" // for get_chip_mac +#include "esp_log.h" static const char *tag = "BLE_SP110E"; @@ -33,7 +36,6 @@ TaskHandle_t LightStick_Client_Task_Handle = NULL; //#define UPGRADE_SERVICE_UUID "abcdef01-2345-6789-1234-56789abcdef0" //#define UPGRADE_CHARACTERISTIC_UUID "abcdef01-2345-6789-1234-56789abcdef1" - //typedef enum {SM16703,TM1804,UCS1903,WS2811,WS2801,SK6812,LPD6803,LPD8806,APA102,APA105,DMX512,TM1914,TM1913,P9813,INK1003,P943S,P9411,P9413,TX1812,TX1813,GS8206,GS8208,SK9822,TM1814,SK6812_RGBW,P9414,PG412,IC_MODEL_COUNT } IC_MODELS; //typedef enum {RGB,RBG,GRB,GBR,BRG,BGR,SEQUENCE_COUNT} SEQUENCES; @@ -133,6 +135,78 @@ public: process_BLE_SP110E_Command(data, procLen, pCharacteristic); } + // Respond to read requests by returning the current led_status structure + void onRead(NimBLECharacteristic* pCharacteristic) override { + if (!pCharacteristic) return; + + USER_SETTINGS userSettings = {}; + + userSettings.cmd = 0; // Indicate this is a status response + userSettings.limitedMode = sys_settings.limitedMode ? 1 : 0; + userSettings.profile[9] = '\0'; // Ensure null-terminated + { + // sys_settings.profile is an Arduino String; use c_str() to obtain a const char* + const char* src = sys_settings.profile.c_str(); + // copy up to size-1 characters to ensure null-termination + size_t maxCopy = sizeof(userSettings.profile) - 1; + size_t srcLen = strlen(src); + size_t copyLen = srcLen < maxCopy ? srcLen : maxCopy; + if (copyLen) memcpy(userSettings.profile, src, copyLen); + // null terminate right after copied data + userSettings.profile[copyLen] = '\0'; + // ensure the remaining bytes are zeroed out + for (size_t i = copyLen + 1; i < sizeof(userSettings.profile); ++i) userSettings.profile[i] = '\0'; + } + + userSettings.temperature = boardTemperature; // Placeholder, implement actual temperature reading if needed + userSettings.vIn = PowerVin; // Placeholder, implement actual voltage reading if needed + + // Determine chipset with case‐insensitive substring match + std::string chip = std::string(sys_settings.ledStripSettings[0]->chip.c_str()); + std::string chipLower; + chipLower.resize(chip.size()); + std::transform(chip.begin(), chip.end(), chipLower.begin(), [](unsigned char c){ return std::tolower(c); }); + if (chipLower.find("WS2812b") != std::string::npos) userSettings.ledChipset1 = 0; + else if (chipLower.find("SK6812") != std::string::npos) userSettings.ledChipset1 = 1; + else if (chipLower.find("WS2811") != std::string::npos) userSettings.ledChipset1 = 2; + else if (chipLower.find("WS2815") != std::string::npos) userSettings.ledChipset1 = 3; + else userSettings.ledChipset1 = 0; + + + strncpy(userSettings.rgbOrder1, sys_settings.ledStripSettings[0]->rgbOrder.c_str(), 4); + userSettings.ledCount1 = sys_settings.ledStripSettings[0]->size; + userSettings.ledShift1 = sys_settings.ledStripSettings[0]->shift; + userSettings.ledBrightness1= sys_settings.ledStripSettings[0]->bright; + + std::string chip2 = std::string(sys_settings.ledStripSettings[1]->chip.c_str()); + std::string chipLower2; + chipLower2.resize(chip2.size()); + std::transform(chip2.begin(), chip2.end(), chipLower2.begin(), + [](unsigned char c){ return std::tolower(c); }); + if (chipLower2.find("WS2812b") != std::string::npos) userSettings.ledChipset2 = 0; + else if (chipLower2.find("SK6812") != std::string::npos) userSettings.ledChipset2 = 1; + else if (chipLower2.find("WS2811") != std::string::npos) userSettings.ledChipset2 = 2; + else if (chipLower2.find("WS2815") != std::string::npos) userSettings.ledChipset2 = 3; + else userSettings.ledChipset2 = 0; + + strncpy(userSettings.rgbOrder2, sys_settings.ledStripSettings[1]->rgbOrder.c_str(), 4); + userSettings.ledCount2 = sys_settings.ledStripSettings[1]->size; + userSettings.ledShift2 = sys_settings.ledStripSettings[1]->shift; + userSettings.ledBrightness2= sys_settings.ledStripSettings[1]->bright; + + userSettings.frontLightMin = sys_settings.rampLightSettings[0].min; + userSettings.frontLightMax = sys_settings.rampLightSettings[0].max; + userSettings.rearLightMin = sys_settings.rampLightSettings[1].min; + userSettings.rearLightMax = sys_settings.rampLightSettings[1].max; + userSettings.fanLowerTemp = sys_settings.tSensorSettings.setpoint1; + userSettings.fanUpperTemp = sys_settings.tSensorSettings.setpoint2; + + // Provide the full INFO_PACK as the characteristic value so readers get device info + pCharacteristic->setValue((uint8_t *)&userSettings, sizeof(USER_SETTINGS)); + // Do not automatically notify on read (notify is for subscriptions), but keep a log + ESP_LOGD(tag, "onRead: returning INFO_PACK (%zu bytes)", sizeof(INFO_PACK)); + } + private: static void logBytes(const uint8_t* data, size_t len) { if (!data) return; @@ -222,20 +296,24 @@ void sendToAllClients(const uint8_t *data, size_t len) { void process_BLE_SP110E_Command(const uint8_t* val, uint8_t len, NimBLECharacteristic* bleChar) { - if (!val) { - ESP_LOGE(tag, "Null command data received"); - return; - } - - if (len < 4) { - ESP_LOGW(tag, "Command too short: %d bytes, expected at least 4", len); - return; + //uint8_t response[sizeof(INFO_PACK)]; // Use a single response buffer + + if (!val) { ESP_LOGE(tag, "Null command data received"); return;} + if (len < 4) { ESP_LOGW(tag, "Command too short: %d bytes, expected at least 4", len); return; } + + //ESP_LOGI(tag, "USER_SETTING size is: %d", sizeof(USER_SETTINGS)); + + uint8_t command = 0; + if (len == 4){ + command = val[3]; + }else if (len == sizeof(USER_SETTINGS)){ + command = val[0]; + //ESP_LOGI(tag, "Command received: 0x%02X, length: %d", command, len); + //ESP_LOGI(tag, "byte1: %d byte2: %d byte3: %d byte4: %d byte5: %d byte6: %d byte7: %d byte8: %d", + // val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8]); } - uint8_t command = val[3]; - //ESP_LOGI(tag, "Command received: 0x%02X, length: %d", command, len); - - uint8_t response[sizeof(INFO_PACK)]; // Use a single response buffer + ESP_LOGI(tag, "Command received: 0x%02X, data0: %d, data1: %d, data2: %d, length: %d", command, val[0], val[1], val[2], len); // Handle different commands switch (command) { @@ -273,7 +351,7 @@ void process_BLE_SP110E_Command(const uint8_t* val, uint8_t len, NimBLECharacter break; case SET_SPEED: led_status.speed = val[0]; - ESP_LOGI(tag, "Mode set to %d", led_status.speed); + ESP_LOGI(tag, "Speed set to %d", led_status.speed); break; case GET_CHECK_DEVICE: // This prepends a checksum led_status.checksum = calculateChecksum(val); @@ -307,9 +385,42 @@ void process_BLE_SP110E_Command(const uint8_t* val, uint8_t len, NimBLECharacter case SET_DEVICE_NAME: ESP_LOGI(tag, "Set Device Name"); break; + case SET_SHIFT: + RGB_Lights_Set_Animation(SHIFT_INDEX, val[0], val[1], val[2]); + ESP_LOGI(tag, "Set Shift to %d", val[0]); + break; + case SET_USER_SETTINGS:{ + USER_SETTINGS userSettings; + + if (len < sizeof(USER_SETTINGS)) { + ESP_LOGW(tag, "SET_USER_SETTINGS command too short: %d bytes, expected at least %d", len, sizeof(USER_SETTINGS)); + break; + } + memcpy(&userSettings, &val[0], sizeof(USER_SETTINGS) ); + + // Print out all the received settings for debugging + /* + ESP_LOGI(tag, "Received User Settings:"); + ESP_LOGI(tag, " Limited Mode: %d", userSettings.limitedMode); + + ESP_LOGI(tag, " LED Chip Type: %d", userSettings.ledChipset1); + ESP_LOGI(tag, " LED Color Order: %s", userSettings.rgbOrder1); + ESP_LOGI(tag, " LED Count: %d", userSettings.ledCount1); + ESP_LOGI(tag, " LED Shift: %d", userSettings.ledShift1); + ESP_LOGI(tag, " LED Brightness: %d", userSettings.ledBrightness1); + + ESP_LOGI(tag, " Fan Lower Temp: %d", userSettings.fanLowerTemp); + ESP_LOGI(tag, " Fan Upper Temp: %d", userSettings.fanUpperTemp); + */ + + SetAndSaveUserSettings(userSettings); + + } + break; + default: ESP_LOGW(tag, "Unknown command: 0x%02X", command); - break; + break; } } @@ -331,7 +442,7 @@ void Init_BLE_SP110E(NimBLEServer* pServer) { // Create FFE1 Characteristic with WRITE and NOTIFY properties pSP110ECharacteristic = pService->createCharacteristic( BTSP110ECharacteristicUUID.c_str(), - NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::NOTIFY + NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY ); // Register the callback with the characteristic @@ -422,11 +533,8 @@ void BLE_LightStick_Client_Task(void *parameter) { // Get the characteristic. pRemoteCharacteristic = pRemoteService->getCharacteristic(BTStickCharacteristicUUID.c_str()); if (pRemoteCharacteristic != nullptr && pRemoteCharacteristic->canNotify()) { - pRemoteCharacteristic->subscribe(true, [](NimBLERemoteCharacteristic* pRemoteCharacteristic, - uint8_t* pData, size_t length, bool isNotify) { - Serial.print("Notification received: "); - Serial.write(pData, length); - Serial.println(); + pRemoteCharacteristic->subscribe(true, [](NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) { + ESP_LOGD(tag, "Notification received: %zu bytes", length); process_BLE_SP110E_Command(pData, length, nullptr); }); } else { @@ -483,7 +591,7 @@ class MyAdvertisedDeviceCallbacks : public NimBLEAdvertisedDeviceCallbacks { NimBLEDevice::getScan()->stop(); myDevice = advertisedDevice; masterFound = true; - Serial.println("Device found!"); + ESP_LOGE(tag, "Device found!"); } } }; \ No newline at end of file diff --git a/src/BleServer.cpp b/src/BleServer.cpp index 76fb565..0165181 100644 --- a/src/BleServer.cpp +++ b/src/BleServer.cpp @@ -38,35 +38,87 @@ class ServerCallbacks : public NimBLEServerCallbacks { class ServerCallbacks : public NimBLEServerCallbacks { public: - void onConnect(NimBLEServer* /*pServer*/) override { - ESP_LOGI(tag, "Client connected"); - ensureAdvertising("onConnect"); + ServerCallbacks() : connectedClients(0) {} + + void onConnect(NimBLEServer* pServer) override { + // Use server's connected count to avoid double-handling between overloads + int count = 0; + if (pServer) count = pServer->getConnectedCount(); + connectedClients = count; + ESP_LOGI(tag, "Client connected (count=%d) [no-desc overload]", connectedClients); + if (connectedClients == 1) { + NimBLEAdvertising* adv = NimBLEDevice::getAdvertising(); + if (adv && adv->isAdvertising()) { + if (adv->stop()) ESP_LOGI(tag, "Advertising stopped after client connected"); + else ESP_LOGE(tag, "Failed to stop advertising after connect"); + } + } else if (connectedClients > 1) { + ESP_LOGW(tag, "Additional client connected while one is active (no-desc)"); + } Buzzer_Play_Tune(TUNE_CONNECTED, 1); } + // This overload provides connection descriptor details (conn handle) so we can reject extra clients. + void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) override { + // desc contains the connection handle for this new client + int connHandle = desc ? desc->conn_handle : -1; + // Use server's connected count to determine how many clients are attached + int count = 0; + if (pServer) count = pServer->getConnectedCount(); + connectedClients = count; + ESP_LOGI(tag, "Client connected (count=%d) conn_handle=%d", connectedClients, connHandle); + + // If this is the first client, stop advertising so no additional clients can connect + if (connectedClients == 1) { + NimBLEAdvertising* adv = NimBLEDevice::getAdvertising(); + if (adv && adv->isAdvertising()) { + if (adv->stop()) ESP_LOGI(tag, "Advertising stopped after client connected"); + else ESP_LOGE(tag, "Failed to stop advertising after connect"); + } + } else if (connectedClients > 1) { + // Reject this new connection immediately to enforce single-client policy + ESP_LOGW(tag, "Rejecting extra client conn_handle=%d (server count=%d)", connHandle, connectedClients); + if (pServer) { + try { + pServer->disconnect(connHandle); + ESP_LOGI(tag, "Disconnected extra client conn_handle=%d", connHandle); + } catch (...) { + ESP_LOGE(tag, "Exception while disconnecting extra client conn_handle=%d", connHandle); + } + } + // Update connectedClients after rejecting (get fresh count if possible) + if (pServer) connectedClients = pServer->getConnectedCount(); + } + //Buzzer_Play_Tune(TUNE_CONNECTED, 1); + } + void onDisconnect(NimBLEServer* /*pServer*/) override { - ESP_LOGI(tag, "Client disconnected"); - ensureAdvertising("onDisconnect"); + if (connectedClients > 0) connectedClients--; + ESP_LOGI(tag, "Client disconnected (count=%d)", connectedClients); + + // If there are no clients left, restart advertising so a new client can connect + if (connectedClients == 0) { + NimBLEAdvertising* adv = NimBLEDevice::getAdvertising(); + if (!adv) { + ESP_LOGE(tag, "Advertising object unavailable on disconnect"); + return; + } + if (adv->isAdvertising()) { + ESP_LOGD(tag, "Advertising already running on disconnect"); + return; + } + if (adv->start()) { + ESP_LOGI(tag, "Advertising restarted after client disconnect"); + } else { + ESP_LOGE(tag, "Failed to start advertising after disconnect"); + } + } + Buzzer_Play_Tune(TUNE_DISCONNECTED, 1); } private: - void ensureAdvertising(const char* reason) { - NimBLEAdvertising* adv = NimBLEDevice::getAdvertising(); - if (!adv) { - ESP_LOGE(tag, "[%s] Advertising object unavailable", reason); - return; - } - if (adv->isAdvertising()) { - ESP_LOGD(tag, "[%s] Advertising already running", reason); - return; - } - if (adv->start()) { - ESP_LOGI(tag, "[%s] Advertising (re)started", reason); - } else { - ESP_LOGE(tag, "[%s] Failed to start advertising", reason); - } - } + int connectedClients; }; diff --git a/src/BleSettings.cpp b/src/BleSettings.cpp index 33dfebf..3425158 100644 --- a/src/BleSettings.cpp +++ b/src/BleSettings.cpp @@ -70,8 +70,6 @@ void Load_BLE_Settings(const String &configPath) { BTDeviceName += macSuffix[0]; // Add first character BTDeviceName += macSuffix[1]; // Add second character - BTDeviceName = "SP110E"; - ESP_LOGI(tag, "Loaded BLE config: name=%s svc=%s char1=%s stick=%s upg_svc=%s upg1=%s upg2=%s", BTDeviceName.c_str(), BTServiceUUID.c_str(), BTSP110ECharacteristicUUID.c_str(), BTStickCharacteristicUUID.c_str(), BTUpgradeServiceUUID.c_str(), diff --git a/src/PWM_Output.cpp b/src/PWM_Output.cpp index c6ca700..62f4f2e 100644 --- a/src/PWM_Output.cpp +++ b/src/PWM_Output.cpp @@ -3,11 +3,7 @@ #include "global.h" -const char* tag = "pwmout"; - -const float binaryPow[17] = { - 0, 2, 4, 8, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535 -}; +static const char* tag = "pwmout"; PWM_Output::PWM_Output(int8_t pin, uint8_t ch, uint8_t res, uint32_t freq, float maxDuty, bool visionCorrected){ this->currDuty = 0; @@ -15,17 +11,21 @@ PWM_Output::PWM_Output(int8_t pin, uint8_t ch, uint8_t res, uint32_t freq, float this->maxDuty = maxDuty; this->visionCorrected = visionCorrected; this->freq = freq; + this->pin = pin; setResolution(res); pinMode(pin, OUTPUT); uint32_t actualFreq = ledcSetup(ch, freq, res); if (actualFreq != freq) { ESP_LOGE(tag, "pwmOut-> ch:%d ledcSetup failed! Requested freq: %d, Actual freq: %d", ch, freq, actualFreq); + // continue but mark as uninitialized to prevent usage + this->initialized = false; return; } ledcAttachPin(pin, ch); setOutput(this->currDuty); + this->initialized = true; } void PWM_Output::setMaxDuty(float duty) { @@ -41,6 +41,10 @@ void PWM_Output::setMaxDuty(float duty) { // Range is 0 to 100% void PWM_Output::setOutput(float duty){ + if(!this->initialized){ + ESP_LOGW(tag, "setOutput called on uninitialized PWM_Output (ch=%d)", this->ch); + return; + } // Clamp the duty cycle to the range [0.0, maxDuty] if (duty < 0.0) { duty = 0.0; @@ -50,15 +54,14 @@ void PWM_Output::setOutput(float duty){ // calculate correct duty value int outDutyVal; - if(this->visionCorrected){ - outDutyVal = linearizeOutput(duty); - } - else{ + if(this->visionCorrected){ + outDutyVal = linearizeOutput(duty); + } else { outDutyVal = static_cast(duty * this->standardFactor); } - // Clamp to valid resolution range [0, 2^res - 1] - int maxVal = static_cast(binaryPow[this->res]); + // Clamp to valid resolution range [0, (1<res >= 31) ? INT32_MAX : ((1 << this->res) - 1); if (outDutyVal < 0) outDutyVal = 0; if (outDutyVal > maxVal) outDutyVal = maxVal; @@ -72,8 +75,10 @@ void PWM_Output::setFreq(uint32_t fq){ uint32_t newFreq; if(this->freq != fq){ newFreq = ledcChangeFrequency(this->ch, fq, this->res); - if(newFreq){ - this->freq = fq; + if(newFreq > 0){ + this->freq = newFreq; + } else { + ESP_LOGW(tag, "ledcChangeFrequency failed for ch:%d requested:%u", this->ch, fq); } } } @@ -84,8 +89,9 @@ void PWM_Output::setResolution(uint8_t res){ if(this->res > 16) this->res = 16; // Use the clamped resolution when computing factors - this->standardFactor = binaryPow[this->res] * 0.01f; - this->visionFactor = binaryPow[this->res] * 0.0001f; + int maxVal = (this->res >= 31) ? INT32_MAX : ((1 << this->res) - 1); + this->standardFactor = static_cast(maxVal) * 0.01f; + this->visionFactor = static_cast(maxVal) * 0.0001f; ESP_LOGD(tag, "factor=%f, vision=%f", this->standardFactor, this->visionFactor); } diff --git a/src/Ramp_Lights.cpp b/src/Ramp_Lights.cpp index b696ce9..a91e14b 100644 --- a/src/Ramp_Lights.cpp +++ b/src/Ramp_Lights.cpp @@ -14,9 +14,12 @@ RAMP_LIGHT::RAMP_LIGHT(OneButton* button, PWM_Output* pwmOutput, float min, floa button->attachLongPressStop([](void* context) { static_cast(context)->longPressStop(); }, this); button->attachDuringLongPress([](void* context) { static_cast(context)->duringLongPress(); }, this); - if(min < 0.0) min = 0.0; - if(max > 100.0) max = 100.0; - currentValue = min; + + if(min < 0.0) this->min = 0.0; + if(max > 100.0) this->max = 100.0; + if(this->max < this->min) this->max = this->min; + if(step <= 0.0) this->step = 1.0; + currentValue = this->min; IsOn = false; rampState = RampingUp; } @@ -52,11 +55,17 @@ void RAMP_LIGHT::longPressStop(){ void RAMP_LIGHT::duringLongPress(){ if(IsOn){ if (tickCount > 0 && --tickCount == 0) { - // When ramping down, currentValue may go below min if step is large; constrain ensures bounds. - // Ensure currentValue stays within [min, max] bounds for safe PWM operation - currentValue = constrain(currentValue, min, max); - pwmOutput->setOutput(currentValue); - //ESP_LOGD(tag, "duty: %f, sent val: %d, actual val: %d", currentValue, pwmOutput->currOutVal, pwmOutput->getOutVal()); + // Adjust currentValue based on ramp direction + if(rampState == RampingUp){ + currentValue += step; + } else { + currentValue -= step; + } + + // Constrain and apply + currentValue = constrain(currentValue, this->min, this->max); + if(pwmOutput) pwmOutput->setOutput(currentValue); + ESP_LOGD(tag, "duty: %f, sent val: %d, actual val: %d", currentValue, pwmOutput? pwmOutput->currOutVal : -1, pwmOutput? pwmOutput->getOutVal() : -1); tickCount = TickDelayCount; } } diff --git a/src/common/fileSystem.cpp b/src/common/fileSystem.cpp index 73c4d6a..3120d67 100644 --- a/src/common/fileSystem.cpp +++ b/src/common/fileSystem.cpp @@ -23,23 +23,31 @@ void Init_File_System(void){ //printAllSystemFiles(); } -void getAllDirectories(String (&directoryList)[MAX_DIRECTORIES], int &count){ +void getAllDirectories(String directoryList[], int &count){ File root = LittleFS.open("/"); if (!root || !root.isDirectory()){ ESP_LOGE("FileSystem", "Failed to open root directory or root is not a directory"); return; } + // Initialize with root directory + if (MAX_DIRECTORIES <= 0) { + ESP_LOGW("FileSystem", "MAX_DIRECTORIES is not set or invalid"); + root.close(); + return; + } directoryList[0] = "/"; count = 1; File file = root.openNextFile(); while (file) { if (file.isDirectory()){ - if (count < 10){ // Ensure we don't overflow the array - directoryList[count] = '/' + String(file.name()); + if (count < MAX_DIRECTORIES){ // Ensure we don't overflow the caller's array + String entry = String(file.name()); + if (!entry.startsWith("/")) entry = "/" + entry; + directoryList[count] = entry; count++; - }else{ + } else { ESP_LOGW("FileSystem", "Directory list array is full"); break; } diff --git a/src/common/fileSystem.h b/src/common/fileSystem.h index 13a1414..1a5cfbc 100644 --- a/src/common/fileSystem.h +++ b/src/common/fileSystem.h @@ -15,7 +15,7 @@ void writeFilesToSerial(void); //void getAllDirectoriesRecursive(const String& path, String directoryList[], int& count, int maxSize); //void getAllDirectories(String directoryList[], int& count, int maxSize); -void getAllDirectories(String (&directoryList)[MAX_DIRECTORIES], int& count); +void getAllDirectories(String directoryList[], int& count); void printFilesInDirectories(const String directoryList[], int count); diff --git a/src/global.cpp b/src/global.cpp index b0bdf77..fa1447b 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -412,4 +412,9 @@ void print_task_watermarks(void) { } else { ESP_LOGE(tag, "Failed to get current task handle"); } -} \ No newline at end of file +} + + +float updateLowpass(float currentValue, float newValue, float alpha) { + return (alpha * newValue) + ((1 - alpha) * currentValue); +} diff --git a/src/main.cpp b/src/main.cpp index 028827f..89f0ca5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -82,6 +82,9 @@ TimerHandle_t upgradeHeartbeatTimer = NULL; TimerHandle_t diagnosticsTimer = NULL; #define diagnosticsInterval 60000 // ms +TimerHandle_t analogInputTimer = NULL; +#define analogInputInterval 3000 // ms + void setupLogLevels(esp_log_level_t logLevel); @@ -120,6 +123,13 @@ void DiagnosticsCallback(TimerHandle_t xTimer) { #endif } +void AnalogInputCallback(TimerHandle_t xTimer) { + float v = readBoardInputVoltage(); + PowerVin = updateLowpass(prevPowerVin, v*1.01, PowerVinAlpha); + prevPowerVin = PowerVin; + //ESP_LOGI(tag, "Input Voltage = %f", PowerVin); +} + void checkLEDCChannels() { @@ -167,7 +177,7 @@ void setup() printAllSystemFiles(); } - String board_file_path, booth_file_path; + String board_file_path; Get_Board_and_Booth_File_Paths("/system/system.json", board_file_path, booth_file_path); // Load Board Pins @@ -205,15 +215,10 @@ void setup() // Initialize Temperature Sensor Init_TSensor(72, &sys_settings.tSensorSettings); - - float val = readBoardInputVoltage(); - ESP_LOGI(tag, "Input Volage = %f", val); - // Initialize BLE & Wifi // If button 1 is held during boot, enable upgrade mode Load_BLE_Settings("/system/ble.json"); - if (digitalRead(sys_settings.boardPins.btn[0]) == LOW) - { + if (digitalRead(sys_settings.boardPins.btn[0]) == LOW){ setStatusPin1(true); ESP_LOGW(tag, "Upgrade Mode Triggered"); ESP_LOGW(tag, "Enabling BLE and Update Service"); @@ -223,8 +228,7 @@ void setup() UpgradeMode = true; upgradeHeartbeatTimer = xTimerCreate("UpgradeHeartbeat", pdMS_TO_TICKS(5000), pdTRUE, NULL, UpgradeHeartbeatCallback); } - else - { + else { ESP_LOGI(tag, "Enabling BLE, No Update Service"); Init_BleServer(true, false); // Dont start the Upgrade service } @@ -236,20 +240,18 @@ void setup() } #if OLED_ENABLED - // Init OLED Init_OLED(sys_settings.oledSettings.width, sys_settings.oledSettings.height, sys_settings.boardPins.oled_mosi, sys_settings.boardPins.oled_sck, sys_settings.boardPins.oled_dc, sys_settings.boardPins.oled_rst, sys_settings.boardPins.oled_cs); #endif #if STRIPS_ENABLED - Init_RGB_Lights_Task(); - //vTaskDelay(100); - //Init_Ramp_Front_Light_Task(); + Init_RGB_Lights_Task(UpgradeMode); #endif // Create and start software timers buttonScanTimer = xTimerCreate("ButtonScan", pdMS_TO_TICKS(buttonScanInterval), pdTRUE, NULL, ButtonScanCallback); temperatureTimer = xTimerCreate("Temperature", pdMS_TO_TICKS(sys_settings.tSensorSettings.intervalMs), pdTRUE, NULL, TemperatureCallback); statusLedTimer = xTimerCreate("StatusLED", pdMS_TO_TICKS(statusLedInterval), pdTRUE, NULL, StatusLedCallback); + analogInputTimer = xTimerCreate("AnalogInput", pdMS_TO_TICKS(analogInputInterval), pdTRUE, NULL, AnalogInputCallback); #if FREERTOs_DIAGNOSTICS @@ -257,10 +259,11 @@ void setup() #endif // Start the timers - if (buttonScanTimer) xTimerStart(buttonScanTimer, 25); + //if (buttonScanTimer) xTimerStart(buttonScanTimer, 100); if (temperatureTimer && sys_settings.tSensorSettings.enabled) xTimerStart(temperatureTimer, 100); if (statusLedTimer) xTimerStart(statusLedTimer, 0); if (upgradeHeartbeatTimer && UpgradeMode) xTimerStart(upgradeHeartbeatTimer, upgradeHeartbeatInterval); + if (analogInputTimer) xTimerStart(analogInputTimer, 0); #if FREERTOS_DIAGNOSTICS if (diagnosticsTimer) xTimerStart(diagnosticsTimer, diagnosticsInterval); @@ -315,9 +318,20 @@ void loop() } } #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(pdMS_TO_TICKS(100)); + + vTaskDelay(portMAX_DELAY); } void setupLogLevels(esp_log_level_t logLevel) diff --git a/src/my_board.cpp b/src/my_board.cpp index bf7a7fc..b73d6fc 100644 --- a/src/my_board.cpp +++ b/src/my_board.cpp @@ -4,124 +4,143 @@ #include #include -#include "global.h" #include "JsonConstrain.h" +#include "global.h" #include "system.h" -static const char* tag = "board"; +static const char *tag = "board"; -BOARD_PINS* thisBoardPins; +BOARD_PINS *thisBoardPins = nullptr; // Basic validator for ESP32-S3 GPIOs; rejects common reserved/USB/strap pins static bool isValidGpio(int pin) { - if (pin < 0 || pin > 48) return false; - switch (pin) { + if (pin < 0 || pin > 48) + return false; + switch (pin) { case 19: // USB D- case 20: // USB D+ case 45: // strapping case 46: // strapping - return false; + return false; default: - return true; - } + return true; + } } -bool Load_Board_Pins(BOARD_PINS& boardPins, const String& path){ - // Default initialize to -1 to avoid stale values on partial loads - memset(&boardPins, -1, sizeof(boardPins)); - thisBoardPins = &boardPins; - File file = LittleFS.open(path); +bool Load_Board_Pins(BOARD_PINS &boardPins, const String &path) { + // Default initialize to -1 to avoid stale values on partial loads + memset(&boardPins, -1, sizeof(boardPins)); + thisBoardPins = &boardPins; + File file = LittleFS.open(path); - if (!file) { - ESP_LOGE(tag, "Error opening %s...", path.c_str()); - return false; - } + if (!file) { + ESP_LOGE(tag, "Error opening %s...", path.c_str()); + return false; + } - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); + JsonDocument doc; + DeserializationError error = deserializeJson(doc, file); + file.close(); - if (error) { - ESP_LOGE(tag, "%s deserialize error!..", path.c_str()); - return false; - } + if (error) { + ESP_LOGE(tag, "%s deserialize error: %s", path.c_str(), error.c_str()); + return false; + } - JsonObject boardJson = doc.as(); - boardPins.rgb1 = jsonConstrain(tag, boardJson, "rgb1", -1, 48, -1); - boardPins.rgb2 = jsonConstrain(tag, boardJson, "rgb2", -1, 48, -1); - boardPins.btn[0] = jsonConstrain(tag, boardJson, "btn1", -1, 48, -1); - boardPins.btn[1] = jsonConstrain(tag, boardJson, "btn2", -1, 48, -1); - boardPins.btn[2] = jsonConstrain(tag, boardJson, "btn3", -1, 48, -1); - boardPins.buzzer = jsonConstrain(tag, boardJson, "buzzer", -1, 48, -1); - boardPins.touch[0] = jsonConstrain(tag, boardJson, "touch1", -1, 48, -1); - boardPins.touch[1] = jsonConstrain(tag, boardJson, "touch2", -1, 48, -1); - boardPins.touch[2] = jsonConstrain(tag, boardJson, "touch3", -1, 48, -1); - boardPins.touch[3] = jsonConstrain(tag, boardJson, "touch4", -1, 48, -1); - boardPins.touch[4] = jsonConstrain(tag, boardJson, "touch5", -1, 48, -1); - boardPins.shield = jsonConstrain(tag, boardJson, "shield", -1, 48, -1); - boardPins.relay[0] = jsonConstrain(tag, boardJson, "relay1", -1, 48, -1); - boardPins.relay[1] = jsonConstrain(tag, boardJson, "relay2", -1, 48, -1); - boardPins.relay[2] = jsonConstrain(tag, boardJson, "relay3", -1, 48, -1); - boardPins.relay[3] = jsonConstrain(tag, boardJson, "relay4", -1, 48, -1); - boardPins.stat[0] = jsonConstrain(tag, boardJson, "stat1", -1, 48, -1); - boardPins.stat[1] = jsonConstrain(tag, boardJson, "stat2", -1, 48, -1); - boardPins.adc1 = jsonConstrain(tag, boardJson, "adc1", -1, 48, -1); - boardPins.oled_dc = jsonConstrain(tag, boardJson, "oled_dc", -1, 48, -1); - boardPins.oled_rst = jsonConstrain(tag, boardJson, "oled_rst", -1, 48, -1); - boardPins.oled_mosi = jsonConstrain(tag, boardJson, "oled_mosi", -1, 48, -1); - boardPins.oled_sck = jsonConstrain(tag, boardJson, "oled_sck", -1, 48, -1); - boardPins.oled_cs = jsonConstrain(tag, boardJson, "oled_cs", -1, 48, -1); - boardPins.ext[0] = jsonConstrain(tag, boardJson, "ext1", -1, 48, -1); - boardPins.ext[1] = jsonConstrain(tag, boardJson, "ext2", -1, 48, -1); - boardPins.rf433tx = jsonConstrain(tag, boardJson, "rf433tx", -1, 48, -1); - boardPins.rf433rx = jsonConstrain(tag, boardJson, "rf433rx", -1, 48, -1); + JsonObject boardJson = doc.as(); + boardPins.rgb1 = jsonConstrain(tag, boardJson, "rgb1", -1, 48, -1); + boardPins.rgb2 = jsonConstrain(tag, boardJson, "rgb2", -1, 48, -1); + boardPins.btn[0] = jsonConstrain(tag, boardJson, "btn1", -1, 48, -1); + boardPins.btn[1] = jsonConstrain(tag, boardJson, "btn2", -1, 48, -1); + boardPins.btn[2] = jsonConstrain(tag, boardJson, "btn3", -1, 48, -1); + boardPins.buzzer = jsonConstrain(tag, boardJson, "buzzer", -1, 48, -1); + boardPins.touch[0] = jsonConstrain(tag, boardJson, "touch1", -1, 48, -1); + boardPins.touch[1] = jsonConstrain(tag, boardJson, "touch2", -1, 48, -1); + boardPins.touch[2] = jsonConstrain(tag, boardJson, "touch3", -1, 48, -1); + boardPins.touch[3] = jsonConstrain(tag, boardJson, "touch4", -1, 48, -1); + boardPins.touch[4] = jsonConstrain(tag, boardJson, "touch5", -1, 48, -1); + boardPins.shield = jsonConstrain(tag, boardJson, "shield", -1, 48, -1); + boardPins.relay[0] = jsonConstrain(tag, boardJson, "relay1", -1, 48, -1); + boardPins.relay[1] = jsonConstrain(tag, boardJson, "relay2", -1, 48, -1); + boardPins.relay[2] = jsonConstrain(tag, boardJson, "relay3", -1, 48, -1); + boardPins.relay[3] = jsonConstrain(tag, boardJson, "relay4", -1, 48, -1); + boardPins.stat[0] = jsonConstrain(tag, boardJson, "stat1", -1, 48, -1); + boardPins.stat[1] = jsonConstrain(tag, boardJson, "stat2", -1, 48, -1); + boardPins.adc1 = jsonConstrain(tag, boardJson, "adc1", -1, 48, -1); + boardPins.oled_dc = jsonConstrain(tag, boardJson, "oled_dc", -1, 48, -1); + boardPins.oled_rst = jsonConstrain(tag, boardJson, "oled_rst", -1, 48, -1); + boardPins.oled_mosi = jsonConstrain(tag, boardJson, "oled_mosi", -1, 48, -1); + boardPins.oled_sck = jsonConstrain(tag, boardJson, "oled_sck", -1, 48, -1); + boardPins.oled_cs = jsonConstrain(tag, boardJson, "oled_cs", -1, 48, -1); + boardPins.ext[0] = jsonConstrain(tag, boardJson, "ext1", -1, 48, -1); + boardPins.ext[1] = jsonConstrain(tag, boardJson, "ext2", -1, 48, -1); + boardPins.rf433tx = jsonConstrain(tag, boardJson, "rf433tx", -1, 48, -1); + boardPins.rf433rx = jsonConstrain(tag, boardJson, "rf433rx", -1, 48, -1); - // Validate pins against reserved GPIOs - auto clampPin = [](int v){ return isValidGpio(v) ? v : -1; }; - boardPins.rgb1 = clampPin(boardPins.rgb1); - boardPins.rgb2 = clampPin(boardPins.rgb2); - for (int i=0;i<3;i++) boardPins.btn[i] = clampPin(boardPins.btn[i]); - boardPins.buzzer = clampPin(boardPins.buzzer); - for (int i=0;i<5;i++) boardPins.touch[i] = clampPin(boardPins.touch[i]); - boardPins.shield = clampPin(boardPins.shield); - for (int i=0;i<4;i++) boardPins.relay[i] = clampPin(boardPins.relay[i]); - for (int i=0;i<2;i++) boardPins.stat[i] = clampPin(boardPins.stat[i]); - boardPins.adc1 = clampPin(boardPins.adc1); - boardPins.oled_dc = clampPin(boardPins.oled_dc); - boardPins.oled_rst = clampPin(boardPins.oled_rst); - boardPins.oled_mosi = clampPin(boardPins.oled_mosi); - boardPins.oled_sck = clampPin(boardPins.oled_sck); - boardPins.oled_cs = clampPin(boardPins.oled_cs); - for (int i=0;i<2;i++) boardPins.ext[i] = clampPin(boardPins.ext[i]); - boardPins.rf433tx = clampPin(boardPins.rf433tx); - boardPins.rf433rx = clampPin(boardPins.rf433rx); + // Validate pins against reserved GPIOs + auto clampPin = [](int v) { return isValidGpio(v) ? v : -1; }; + boardPins.rgb1 = clampPin(boardPins.rgb1); + boardPins.rgb2 = clampPin(boardPins.rgb2); + for (int i = 0; i < 3; i++) + boardPins.btn[i] = clampPin(boardPins.btn[i]); + boardPins.buzzer = clampPin(boardPins.buzzer); + for (int i = 0; i < 5; i++) + boardPins.touch[i] = clampPin(boardPins.touch[i]); + boardPins.shield = clampPin(boardPins.shield); + for (int i = 0; i < 4; i++) + boardPins.relay[i] = clampPin(boardPins.relay[i]); + for (int i = 0; i < 2; i++) + boardPins.stat[i] = clampPin(boardPins.stat[i]); + boardPins.adc1 = clampPin(boardPins.adc1); + boardPins.oled_dc = clampPin(boardPins.oled_dc); + boardPins.oled_rst = clampPin(boardPins.oled_rst); + boardPins.oled_mosi = clampPin(boardPins.oled_mosi); + boardPins.oled_sck = clampPin(boardPins.oled_sck); + boardPins.oled_cs = clampPin(boardPins.oled_cs); + for (int i = 0; i < 2; i++) + boardPins.ext[i] = clampPin(boardPins.ext[i]); + boardPins.rf433tx = clampPin(boardPins.rf433tx); + boardPins.rf433rx = clampPin(boardPins.rf433rx); - ESP_LOGI(tag, "loaded Pins from %s", path.c_str()); - return true; + ESP_LOGI(tag, "loaded Pins from %s", path.c_str()); + return true; } +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[1] >= 0){ pinMode(boardPins.stat[1], OUTPUT); } + if (boardPins.stat[0] >= 0) { + pinMode(boardPins.stat[0], OUTPUT); + } + if (boardPins.stat[1] >= 0) { + pinMode(boardPins.stat[1], 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.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); + } - if(boardPins.btn[0] >= 0){ pinMode(boardPins.btn[0], INPUT_PULLUP); } - if(boardPins.btn[1] >= 0){ 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..."); } - - - - diff --git a/src/my_buttons.cpp b/src/my_buttons.cpp index 39d945f..151d2bf 100644 --- a/src/my_buttons.cpp +++ b/src/my_buttons.cpp @@ -5,11 +5,10 @@ #include "AppUpgrade.h" static const char* tag = "button"; -OneButton *boardButtons[3]; +OneButton *boardButtons[3] = { nullptr, nullptr, nullptr }; void Init_ButtonEvents(int8_t (&pin)[3]){ - - + // Initialize buttons if pins are valid and not already initialized if (pin[0] >= 0) { if (boardButtons[0] == nullptr) { boardButtons[0] = new OneButton(pin[0], true, true); diff --git a/src/my_buzzer.cpp b/src/my_buzzer.cpp index 930b82f..2d9918e 100644 --- a/src/my_buzzer.cpp +++ b/src/my_buzzer.cpp @@ -17,7 +17,7 @@ static const char* tag = "buzzer"; // Define static constexpr member from RtttlPlayer class constexpr uint16_t RtttlPlayer::LUT4[12]; -RtttlPlayer *player; +RtttlPlayer *player = nullptr; BUZZ_TUNE buzzTune[TUNE_MAX_COUNT]; int8_t buzzPin; int8_t buzzerChannel = -1; // Store the LEDC channel used by the buzzer @@ -105,7 +105,7 @@ void Buzzer_Load_Tunes(const char* tunesPath){ buzzTune[tuneIndex].cycles = jsonConstrain(tag, obj, "cycles", 1, 100, 1); buzzTune[tuneIndex].pause = jsonConstrain(tag, obj, "pause", 0, 100, 0); buzzTune[tuneIndex].melody = jsonConstrainString(tag, obj, "tune", DEFAULT_MELODY); - ESP_LOGI(tag, "Loaded tune %d: cycles=%d, pause=%d, melody=%.40s...", + ESP_LOGD(tag, "Loaded tune %d: cycles=%d, pause=%d, melody=%.40s...", tuneIndex, buzzTune[tuneIndex].cycles, buzzTune[tuneIndex].pause, buzzTune[tuneIndex].melody.c_str()); tuneIndex++; diff --git a/src/my_device.cpp b/src/my_device.cpp index c2a477e..3c90010 100644 --- a/src/my_device.cpp +++ b/src/my_device.cpp @@ -1,79 +1,94 @@ #include "my_device.h" #include "JsonConstrain.h" -#include "global.h" -#include "system.h" -#include "my_buttons.h" #include "PWM_Output.h" #include "Ramp_Lights.h" #include "esp_log.h" -#include -#include +#include "global.h" +#include "my_buttons.h" +#include "system.h" #include #include -#include -#include -#include +#include +#include +#include #include #include -#include +#include +#include +#include #include #include static const char *tag = "my_device"; SYS_SETTINGS sys_settings; -PWM_Output *pwmOutputs[4]; -RAMP_LIGHT *rampLight1; -RAMP_LIGHT *rampLight2; +PWM_Output *pwmOutputs[4] = { nullptr, nullptr, nullptr, nullptr }; +RAMP_LIGHT *rampLight1 = nullptr; +RAMP_LIGHT *rampLight2 = nullptr; + +String booth_file_path; + +float PowerVinAlpha = 0.5; // Low-pass filter alpha +float prevPowerVin = 0.0; +float PowerVin = 0.0; + + // TODO Restore original setOutput code.. #define RELAY_RES 10 -void Init_PWM_Outputs(int8_t (&pin)[4], PWM_OUT_SETTINGS (&pwmSettings)[4]) -{ - // Initialize all pointers to nullptr first +void Init_PWM_Outputs(int8_t (&pin)[4], PWM_OUT_SETTINGS (&pwmSettings)[4]) { + // Delete any existing objects to avoid leaks on re-init for (int i = 0; i < 4; i++) { - pwmOutputs[i] = nullptr; + if (pwmOutputs[i]) { + delete pwmOutputs[i]; + pwmOutputs[i] = nullptr; + } } - - for (int i = 0; i < 4; i++) - { + + for (int i = 0; i < 4; i++) { int chIndex = findUnusedLedcChannel(); - if (chIndex < 0) - { + if (chIndex < 0) { ESP_LOGE(tag, "No available LEDC channel for PWM Output%d", i); continue; } - pwmOutputs[i] = new PWM_Output(pin[i], chIndex, RELAY_RES, pwmSettings[i].freq, pwmSettings[i].max, false); - pwmOutputs[i]->setOutput(pwmSettings[i].def); + pwmOutputs[i] = new PWM_Output(pin[i], chIndex, RELAY_RES, pwmSettings[i].freq, + pwmSettings[i].max, false); + if (pwmOutputs[i]) { + pwmOutputs[i]->setOutput(pwmSettings[i].def); + } else { + ESP_LOGE(tag, "Allocation failed for PWM Output%d", i); + } // pwmOutputs[i]->setOutput(5.0); - ESP_LOGI(tag, "PWM Output%d: Pin=%d, Freq=%d, ch=%d", i, pin[i], pwmSettings[i].freq, chIndex); + ESP_LOGI(tag, "PWM Output%d: Pin=%d, Freq=%d, ch=%d", i, pin[i], pwmSettings[i].freq, + chIndex); } } - -void Init_Ramp_Lights(RAMP_LIGHT_SETTINGS (&settings)[2], OneButton *(&btn)[3], PWM_Output *(&pwm)[4]) -{ - if (settings[0].enabled) - { - rampLight1 = new RAMP_LIGHT(btn[settings[0].btnIndex], pwm[settings[0].pwmOutIndex], settings[0].min, settings[0].max, settings[0].step); - ESP_LOGD(tag, "RampLight%d: btn=%d, pwmIndex=%d", 1, settings[0].btnIndex, settings[0].pwmOutIndex); +void Init_Ramp_Lights(RAMP_LIGHT_SETTINGS (&settings)[2], OneButton *(&btn)[3], PWM_Output *(&pwm)[4]) { + if (settings[0].enabled) { + if (rampLight1) { delete rampLight1; rampLight1 = nullptr; } + rampLight1 = new RAMP_LIGHT(btn[settings[0].btnIndex], pwm[settings[0].pwmOutIndex], settings[0].min, settings[0].max, settings[0].step); + if (rampLight1) + 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); + else + ESP_LOGE(tag, "Failed to allocate RampLight1"); } - if (settings[1].enabled) - { - rampLight2 = new RAMP_LIGHT(btn[settings[1].btnIndex], pwm[settings[1].pwmOutIndex], settings[1].min, settings[1].max, settings[1].step); - ESP_LOGD(tag, "RampLight%d: btn=%d, pwmIndex=%d", 2, settings[1].btnIndex, settings[1].pwmOutIndex); + 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"); } } - // Get the files that should be used to setup the system -void Get_Board_and_Booth_File_Paths(const char *sysPath, String &boardPath, String &boothPath) -{ +void Get_Board_and_Booth_File_Paths(const char *sysPath, String &boardPath, String &boothPath) { File file = LittleFS.open(sysPath); - if (!file) - { + if (!file) { ESP_LOGE(tag, "Error opening %s...", sysPath); return; } @@ -82,23 +97,21 @@ void Get_Board_and_Booth_File_Paths(const char *sysPath, String &boardPath, Stri DeserializationError error = deserializeJson(doc, file); file.close(); - if (error) - { + if (error) { ESP_LOGE(tag, "%s deserialize error!..", sysPath); return; } // get hardware version string - boardPath = jsonConstrainString(tag, doc.as(), "boardfile", "/cfg/boards/board15.json"); - boothPath = jsonConstrainString(tag, doc.as(), "configfile", "/cfg/booths/custom.json"); + boardPath = + jsonConstrainString(tag, doc.as(), "boardfile", "/cfg/boards/board15.json"); + boothPath = + jsonConstrainString(tag, doc.as(), "configfile", "/cfg/booths/custom.json"); } - -void Load_Booth_Settings(SYS_SETTINGS &sys, const String &boothPath) -{ +void Load_Booth_Settings(SYS_SETTINGS &sys, const String &boothPath) { File file = LittleFS.open(boothPath); - if (!file) - { + if (!file) { ESP_LOGE(tag, "Error opening %s...", boothPath.c_str()); return; } @@ -107,139 +120,150 @@ void Load_Booth_Settings(SYS_SETTINGS &sys, const String &boothPath) DeserializationError error = deserializeJson(doc, file); file.close(); - if (error) - { + if (error) { ESP_LOGE(tag, "%s deserialize error!..", boothPath.c_str()); return; } + sys_settings.profile = jsonConstrainString(tag, doc.as(), "profile", "custom"); + // ********** Mode *********** String modeStr = jsonConstrainString(tag, doc.as(), "mode", "booth"); - if (modeStr == "roamer") - { + if (modeStr == "roamer") { sys_settings.mode = BOOTH_MODE_ROAMER; - } - else if (modeStr == "stik") - { + } else if (modeStr == "stik") { sys_settings.mode = BOOTH_MODE_STIK; - } - else - { + } else { sys_settings.mode = BOOTH_MODE_NONE; } // ********** PWM Out *********** JsonArray pwmJsonArray = doc["pwmout"]; - if (!pwmJsonArray.isNull()) - { + if (!pwmJsonArray.isNull()) { int pwmIndex = 0; - for (JsonObject obj : pwmJsonArray) - { - if (pwmIndex >= sizeof(sys_settings.pwmOutSettings) / sizeof(sys_settings.pwmOutSettings[0])) + for (JsonObject obj : pwmJsonArray) { + if (pwmIndex >= + sizeof(sys_settings.pwmOutSettings) / sizeof(sys_settings.pwmOutSettings[0])) break; sys_settings.pwmOutSettings[pwmIndex].enabled = jsonConstrainBool(tag, obj, "en", true); - sys_settings.pwmOutSettings[pwmIndex].freq = jsonConstrain(tag, obj, "freq", 100, 5000, 250); - sys_settings.pwmOutSettings[pwmIndex].min = jsonConstrain(tag, obj, "min", 0.0, 95.0, 0.0); - sys_settings.pwmOutSettings[pwmIndex].max = jsonConstrain(tag, obj, "max", 5.0, 100.0, 100.0); - sys_settings.pwmOutSettings[pwmIndex].def = jsonConstrain(tag, obj, "default", 0.0, 100.0, 0.0); + sys_settings.pwmOutSettings[pwmIndex].freq = + jsonConstrain(tag, obj, "freq", 100, 5000, 250); + sys_settings.pwmOutSettings[pwmIndex].min = + jsonConstrain(tag, obj, "min", 0.0, 95.0, 0.0); + sys_settings.pwmOutSettings[pwmIndex].max = + jsonConstrain(tag, obj, "max", 5.0, 100.0, 100.0); + sys_settings.pwmOutSettings[pwmIndex].def = + jsonConstrain(tag, obj, "default", 0.0, 100.0, 0.0); sys_settings.pwmOutSettings[pwmIndex].deltaRate = 1.0; // sys_settings.pwmOutSettings[pwmIndex]. = jsonConstrainBool(tag, obj, "vision", true); pwmIndex++; } ESP_LOGI(tag, "Loaded PWmOutput settings..."); - } - else - { + } else { ESP_LOGE(tag, "Error!, %s key: pwmout not found..", boothPath); } // ********** Ramp Lights *********** JsonArray rampJsonArray = doc["ramp-lights"]; - if (!rampJsonArray.isNull()) - { + if (!rampJsonArray.isNull()) { int rampIndex = 0; - for (JsonObject obj : rampJsonArray) - { - if (rampIndex >= sizeof(sys_settings.rampLightSettings) / sizeof(sys_settings.rampLightSettings[0])) + for (JsonObject obj : rampJsonArray) { + if (rampIndex >= + sizeof(sys_settings.rampLightSettings) / sizeof(sys_settings.rampLightSettings[0])) break; - sys_settings.rampLightSettings[rampIndex].enabled = jsonConstrainBool(tag, obj, "en", true); - sys_settings.rampLightSettings[rampIndex].vision = jsonConstrainBool(tag, obj, "vision", true); - sys_settings.rampLightSettings[rampIndex].pwmOutIndex = jsonConstrain(tag, obj, "relay-index", 0, 1, 0); - sys_settings.rampLightSettings[rampIndex].btnIndex = jsonConstrain(tag, obj, "button-index", 0, 1, 0); - sys_settings.rampLightSettings[rampIndex].min = jsonConstrain(tag, obj, "min", 0.0, 95.0, 0.0); - sys_settings.rampLightSettings[rampIndex].max = jsonConstrain(tag, obj, "max", 5.0, 100.0, 100.0); - sys_settings.rampLightSettings[rampIndex].step = jsonConstrain(tag, obj, "step", 0.1, 10.0, 1.5); + sys_settings.rampLightSettings[rampIndex].enabled = + jsonConstrainBool(tag, obj, "en", true); + sys_settings.rampLightSettings[rampIndex].vision = + jsonConstrainBool(tag, obj, "vision", true); + sys_settings.rampLightSettings[rampIndex].pwmOutIndex = + jsonConstrain(tag, obj, "relay-index", 0, 1, 0); + sys_settings.rampLightSettings[rampIndex].btnIndex = + jsonConstrain(tag, obj, "button-index", 0, 1, 0); + sys_settings.rampLightSettings[rampIndex].min = + jsonConstrain(tag, obj, "min", 0.0, 95.0, 0.0); + sys_settings.rampLightSettings[rampIndex].max = + jsonConstrain(tag, obj, "max", 5.0, 100.0, 100.0); + sys_settings.rampLightSettings[rampIndex].step = + jsonConstrain(tag, obj, "step", 0.1, 10.0, 1.5); rampIndex++; } ESP_LOGI(tag, "Loaded Ramp Lights settings..."); - } - else - { + } else { ESP_LOGE(tag, "Error!, %s key: ramp-lights not found..", boothPath); } // ********** Fan *********** JsonObject sensorJson = doc["t-sensor"]; - if (!sensorJson.isNull()) - { + if (!sensorJson.isNull()) { sys_settings.tSensorSettings.enabled = jsonConstrainBool(tag, sensorJson, "en", true); - sys_settings.tSensorSettings.pwmIndex = jsonConstrain(tag, sensorJson, "relay", 0, 3, 3); - sys_settings.tSensorSettings.setpoint1 = jsonConstrain(tag, sensorJson, "sp1", 50.0, 100.0, 80.0); - sys_settings.tSensorSettings.setpoint2 = jsonConstrain(tag, sensorJson, "sp2", 60.0, 110.0, 90.0); - sys_settings.tSensorSettings.fanPower1 = jsonConstrain(tag, sensorJson, "fan-pwr1", 0.0, 100.0, 50.0); - sys_settings.tSensorSettings.fanPower2 = jsonConstrain(tag, sensorJson, "fan-pwr2", 50.0, 100.0, 50.0); - sys_settings.tSensorSettings.hyst = jsonConstrain(tag, sensorJson, "hyst", 1.0, 10.0, 1.0); - sys_settings.tSensorSettings.intervalMs = jsonConstrain(tag, sensorJson, "interval", 1000, 30000, 5000); + sys_settings.tSensorSettings.pwmIndex = + jsonConstrain(tag, sensorJson, "relay", 0, 3, 3); + sys_settings.tSensorSettings.setpoint1 = + jsonConstrain(tag, sensorJson, "sp1", 50.0, 100.0, 80.0); + sys_settings.tSensorSettings.setpoint2 = + jsonConstrain(tag, sensorJson, "sp2", 60.0, 110.0, 90.0); + sys_settings.tSensorSettings.fanPower1 = + jsonConstrain(tag, sensorJson, "fan-pwr1", 0.0, 100.0, 50.0); + sys_settings.tSensorSettings.fanPower2 = + jsonConstrain(tag, sensorJson, "fan-pwr2", 50.0, 100.0, 50.0); + sys_settings.tSensorSettings.hyst = + jsonConstrain(tag, sensorJson, "hyst", 1.0, 10.0, 1.0); + sys_settings.tSensorSettings.intervalMs = + jsonConstrain(tag, sensorJson, "interval", 1000, 30000, 5000); ESP_LOGI(tag, "Loaded TSensor settings..."); - ESP_LOGI(tag, " SP1: %F, SP2 %F, Hyst: %F", sys_settings.tSensorSettings.setpoint1, sys_settings.tSensorSettings.setpoint2, sys_settings.tSensorSettings.hyst); - } - else - { + ESP_LOGI(tag, " SP1: %F, SP2 %F, Hyst: %F", sys_settings.tSensorSettings.setpoint1, + sys_settings.tSensorSettings.setpoint2, sys_settings.tSensorSettings.hyst); + } else { ESP_LOGE(tag, "Error!, %s key: t-sensor not found..", boothPath); } // ********** RGB Strips *********** JsonArray stripsJsonArray = doc["strips"]; - if (!stripsJsonArray.isNull()) - { + if (!stripsJsonArray.isNull()) { int stripIndex = 0; - for (JsonObject obj : stripsJsonArray) - { + for (JsonObject obj : stripsJsonArray) { if (stripIndex >= 2) break; - sys_settings.ledStripSettings[stripIndex]->enabled = jsonConstrainBool(tag, obj, "en", true); - sys_settings.ledStripSettings[stripIndex]->size = jsonConstrain(tag, obj, "size", 1, 250, 25); - sys_settings.ledStripSettings[stripIndex]->chip = jsonConstrainString(tag, obj, "chip", "WS2812B"); - sys_settings.ledStripSettings[stripIndex]->rgbOrder = jsonConstrainString(tag, obj, "rgb-order", "WS2812B"); - sys_settings.ledStripSettings[stripIndex]->shift = jsonConstrain(tag, obj, "shift", -250, 250, 0); - sys_settings.ledStripSettings[stripIndex]->offset = jsonConstrain(tag, obj, "offset", -250, 250, 0); - sys_settings.ledStripSettings[stripIndex]->bright = jsonConstrain(tag, obj, "bright", 5, 255, 200); - sys_settings.ledStripSettings[stripIndex]->powerDiv = 0; - sys_settings.ledStripSettings[stripIndex]->i2sCh = 0; - sys_settings.ledStripSettings[stripIndex]->core = jsonConstrain(tag, obj, "core", 0, 1, 0); + if (sys_settings.ledStripSettings[stripIndex]) { + sys_settings.ledStripSettings[stripIndex]->enabled = + jsonConstrainBool(tag, obj, "en", true); + sys_settings.ledStripSettings[stripIndex]->size = + jsonConstrain(tag, obj, "size", 1, 250, 25); + sys_settings.ledStripSettings[stripIndex]->chip = + jsonConstrainString(tag, obj, "chip", "WS2812B"); + sys_settings.ledStripSettings[stripIndex]->rgbOrder = + jsonConstrainString(tag, obj, "rgb-order", "WS2812B"); + sys_settings.ledStripSettings[stripIndex]->shift = + jsonConstrain(tag, obj, "shift", -250, 250, 0); + sys_settings.ledStripSettings[stripIndex]->offset = + jsonConstrain(tag, obj, "offset", -250, 250, 0); + sys_settings.ledStripSettings[stripIndex]->bright = + jsonConstrain(tag, obj, "bright", 5, 255, 200); + sys_settings.ledStripSettings[stripIndex]->powerDiv = 0; + sys_settings.ledStripSettings[stripIndex]->i2sCh = 0; + sys_settings.ledStripSettings[stripIndex]->core = + jsonConstrain(tag, obj, "core", 0, 1, 0); + } else { + ESP_LOGW(tag, "ledStripSettings[%d] is null, skipping config", stripIndex); + } stripIndex++; } sys_settings.ledStripSettings[0]->pin = sys_settings.boardPins.rgb1; sys_settings.ledStripSettings[1]->pin = sys_settings.boardPins.rgb2; ESP_LOGI(tag, "Loaded LED Strip settings..."); - } - else - { + } else { ESP_LOGE(tag, "Error!, %s key: strips not found.."); } // ********** BLE *********** JsonObject bleJson = doc["ble"]; - if (!bleJson.isNull()) - { + if (!bleJson.isNull()) { sys_settings.bleSettings.enabled = jsonConstrainBool(tag, bleJson, "en", true); sys_settings.bleSettings.name = jsonConstrainString(tag, bleJson, "name", "ATA_LIGHTS"); ESP_LOGI(tag, "Loaded BLE settings..."); - } - else - { + } else { ESP_LOGE(tag, "Error!, %s key: ble not found..", boothPath); } @@ -255,14 +279,11 @@ void Load_Booth_Settings(SYS_SETTINGS &sys, const String &boothPath) */ } - -void Init_ADC(void) -{ +void Init_ADC(void) { // Configure ADC analogReadResolution(12); // 12-bit ADC analogSetAttenuation(ADC_11db); - if (sys_settings.boardPins.adc1 >= 0) - { + if (sys_settings.boardPins.adc1 >= 0) { analogSetPinAttenuation(sys_settings.boardPins.adc1, ADC_11db); } @@ -271,35 +292,26 @@ void Init_ADC(void) esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 0, &adc_chars); // Check calibration success - if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) - { + if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { ESP_LOGI(tag, "ADC calibration: Using Two Point values from eFuse"); - } - else if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) - { + } else if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) { ESP_LOGI(tag, "ADC calibration: Using reference voltage from eFuse"); - } - else - { + } else { ESP_LOGW(tag, "ADC calibration: Using default reference voltage"); } } - -float readBoardInputVoltage(void) -{ +float readBoardInputVoltage(void) { const int SAMPLES = 64; uint32_t reading = 0; - if (sys_settings.boardPins.adc1 < 0) - { + if (sys_settings.boardPins.adc1 < 0) { ESP_LOGE(tag, "ADC Pin not valid"); return 0.0; } // Multiple readings for averaging - for (int i = 0; i < SAMPLES; i++) - { + for (int i = 0; i < SAMPLES; i++) { reading += analogRead(sys_settings.boardPins.adc1); delayMicroseconds(50); // Small delay between samples } @@ -311,8 +323,15 @@ float readBoardInputVoltage(void) esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adc_chars); voltage_mv = esp_adc_cal_raw_to_voltage(reading, &adc_chars); - // Scale to 12V range - float voltage = (voltage_mv / 1000.0f) * (10470.0f / 470.0f); + // Voltage divider: R1 = 10k (series to input), R2 = 470 (to ground). Measurement is across R2. + // Vin = Vout * (R1 + R2) / R2 + const float R1 = 10000.0f; + const float R2 = 470.0f; + const float dividerFactor = (R1 + R2) / R2; - return voltage; + // Convert mV to V and apply divider factor + float vout = voltage_mv / 1000.0f; + float vin = vout * dividerFactor; + + return vin; } \ No newline at end of file diff --git a/src/my_oled.cpp b/src/my_oled.cpp index 1b8de4d..8857b90 100644 --- a/src/my_oled.cpp +++ b/src/my_oled.cpp @@ -1,24 +1,25 @@ #include "my_oled.h" -#include #include +#include -static const char* tag = "oled"; -Adafruit_SSD1306 *oled; +static const char *tag = "oled"; +Adafruit_SSD1306 *oled = nullptr; -void Init_OLED(uint8_t width, uint8_t height, uint8_t mosiPin, uint8_t sckPin, uint8_t dcPin, uint8_t rstPin, uint8_t csPin) -{ - oled = new Adafruit_SSD1306(width, height, mosiPin, sckPin, dcPin, rstPin, csPin); +void Init_OLED(uint8_t width, uint8_t height, uint8_t mosiPin, uint8_t sckPin, uint8_t dcPin, + uint8_t rstPin, uint8_t csPin) { + oled = new Adafruit_SSD1306(width, height, mosiPin, sckPin, dcPin, rstPin, csPin); - if(!oled->begin(SSD1306_SWITCHCAPVCC)) { - ESP_LOGE(tag, "SSD1306 allocation failed"); - for(;;); // Don't proceed, loop forever - } + if (!oled->begin(SSD1306_SWITCHCAPVCC)) { + ESP_LOGE(tag, "SSD1306 allocation failed"); + for (;;) + ; // Don't proceed, loop forever + } - oled_ShowInfo(); + oled_ShowInfo(); } -void oled_ShowInfo(void){ - //if(sysProps.oledEnabled) { +void oled_ShowInfo(void) { + // if(sysProps.oledEnabled) { oled->display(); vTaskDelay(2000); // Pause for 2 seconds @@ -37,89 +38,89 @@ void oled_ShowInfo(void){ // drawing operations and then update the screen all at once by calling // display.display(). These examples demonstrate both approaches... - //testdrawline(*oled); // Draw many lines + // testdrawline(*oled); // Draw many lines - //testdrawrect(*oled); // Draw rectangles (outlines) + // testdrawrect(*oled); // Draw rectangles (outlines) - testdrawline(oled); // Draw many lines + testdrawline(oled); // Draw many lines - testdrawrect(oled); // Draw rectangles (outlines) - //} + testdrawrect(oled); // Draw rectangles (outlines) + //} } -void testdrawline(Adafruit_SSD1306* display) { - //if(sysProps.oledEnabled) { +void testdrawline(Adafruit_SSD1306 *display) { + // if(sysProps.oledEnabled) { int16_t i; display->clearDisplay(); // Clear display buffer - for(i=0; iwidth(); i+=4) { - display->drawLine(0, 0, i, display->height()-1, SSD1306_WHITE); - display->display(); // Update screen with each newly-drawn line - vTaskDelay(1); + for (i = 0; i < display->width(); i += 4) { + display->drawLine(0, 0, i, display->height() - 1, SSD1306_WHITE); + display->display(); // Update screen with each newly-drawn line + vTaskDelay(1); } - for(i=0; iheight(); i+=4) { - display->drawLine(0, 0, display->width()-1, i, SSD1306_WHITE); - display->display(); - vTaskDelay(1); + for (i = 0; i < display->height(); i += 4) { + display->drawLine(0, 0, display->width() - 1, i, SSD1306_WHITE); + display->display(); + vTaskDelay(1); } vTaskDelay(250); display->clearDisplay(); - for(i=0; iwidth(); i+=4) { - display->drawLine(0, display->height()-1, i, 0, SSD1306_WHITE); - display->display(); - vTaskDelay(1); + for (i = 0; i < display->width(); i += 4) { + display->drawLine(0, display->height() - 1, i, 0, SSD1306_WHITE); + display->display(); + vTaskDelay(1); } - for(i=display->height()-1; i>=0; i-=4) { - display->drawLine(0, display->height()-1, display->width()-1, i, SSD1306_WHITE); - display->display(); - vTaskDelay(1); + for (i = display->height() - 1; i >= 0; i -= 4) { + display->drawLine(0, display->height() - 1, display->width() - 1, i, SSD1306_WHITE); + display->display(); + vTaskDelay(1); } vTaskDelay(250); display->clearDisplay(); - for(i=display->width()-1; i>=0; i-=4) { - display->drawLine(display->width()-1, display->height()-1, i, 0, SSD1306_WHITE); - display->display(); - vTaskDelay(1); + for (i = display->width() - 1; i >= 0; i -= 4) { + display->drawLine(display->width() - 1, display->height() - 1, i, 0, SSD1306_WHITE); + display->display(); + vTaskDelay(1); } - for(i=display->height()-1; i>=0; i-=4) { - display->drawLine(display->width()-1, display->height()-1, 0, i, SSD1306_WHITE); - display->display(); - vTaskDelay(1); + for (i = display->height() - 1; i >= 0; i -= 4) { + display->drawLine(display->width() - 1, display->height() - 1, 0, i, SSD1306_WHITE); + display->display(); + vTaskDelay(1); } vTaskDelay(250); display->clearDisplay(); - for(i=0; iheight(); i+=4) { - display->drawLine(display->width()-1, 0, 0, i, SSD1306_WHITE); - display->display(); - vTaskDelay(1); + for (i = 0; i < display->height(); i += 4) { + display->drawLine(display->width() - 1, 0, 0, i, SSD1306_WHITE); + display->display(); + vTaskDelay(1); } - for(i=0; iwidth(); i+=4) { - display->drawLine(display->width()-1, 0, i, display->height()-1, SSD1306_WHITE); - display->display(); - vTaskDelay(1); + for (i = 0; i < display->width(); i += 4) { + display->drawLine(display->width() - 1, 0, i, display->height() - 1, SSD1306_WHITE); + display->display(); + vTaskDelay(1); } vTaskDelay(2000); // Pause for 2 seconds - //} + //} } -void testdrawrect(Adafruit_SSD1306* display) { - //if(sysProps.oledEnabled) { +void testdrawrect(Adafruit_SSD1306 *display) { + // if(sysProps.oledEnabled) { display->clearDisplay(); - for(int16_t i=0; iheight()/2; i+=2) { - display->drawRect(i, i, display->width()-2*i, display->height()-2*i, SSD1306_WHITE); - display->display(); // Update screen with each newly-drawn rectangle - vTaskDelay(1); + for (int16_t i = 0; i < display->height() / 2; i += 2) { + display->drawRect(i, i, display->width() - 2 * i, display->height() - 2 * i, SSD1306_WHITE); + display->display(); // Update screen with each newly-drawn rectangle + vTaskDelay(1); } vTaskDelay(2000); - //} + //} } \ No newline at end of file diff --git a/src/my_tsensor.cpp b/src/my_tsensor.cpp index 7cbf218..6421e9b 100644 --- a/src/my_tsensor.cpp +++ b/src/my_tsensor.cpp @@ -21,7 +21,7 @@ void Init_TSensor(uint8_t addr, TSENSOR_SETTINGS *tsettings) { // Initialize the temperature sensor once with the provided I2C address if (tSensor == nullptr) { tSensor = new TI_TMP102_Compatible(addr); - ESP_LOGI(tag, "TSensor initialized at I2C addr 0x%02X", addr); + ESP_LOGD(tag, "TSensor initialized at I2C addr 0x%02X", addr); } else { ESP_LOGW(tag, "TSensor already initialized; ignoring re-init request (addr 0x%02X)", addr); } @@ -77,7 +77,7 @@ void Init_TSensor(uint8_t addr, TSENSOR_SETTINGS *tsettings) { // Fan is off - check if we should turn it on if (temperature >= sp1) { fanIsOn = true; - ESP_LOGI(tag, "Fan turning ON - temp %.2f >= setpoint1 %.2f", temperature, sp1); + ESP_LOGD(tag, "Fan turning ON - temp %.2f >= setpoint1 %.2f", temperature, sp1); } else { newDuty = 0.0f; // Stay off } @@ -86,7 +86,7 @@ void Init_TSensor(uint8_t addr, TSENSOR_SETTINGS *tsettings) { if (temperature < (sp1 - hyst)) { fanIsOn = false; newDuty = 0.0f; - ESP_LOGI(tag, "Fan turning OFF - temp %.2f < (setpoint1 - hyst) %.2f", temperature, sp1 - hyst); + ESP_LOGD(tag, "Fan turning OFF - temp %.2f < (setpoint1 - hyst) %.2f", temperature, sp1 - hyst); } } @@ -105,7 +105,7 @@ void Init_TSensor(uint8_t addr, TSENSOR_SETTINGS *tsettings) { float tempRatio = (temperature - sp1) / tempRange; newDuty = fp1 + (tempRatio * powerRange); - ESP_LOGV(tag, "Linear scaling: temp=%.2f, ratio=%.3f, duty=%.2f", temperature, tempRatio, newDuty); + ESP_LOGD(tag, "Linear scaling: temp=%.2f, ratio=%.3f, duty=%.2f", temperature, tempRatio, newDuty); } // Ensure duty is within bounds @@ -115,7 +115,7 @@ void Init_TSensor(uint8_t addr, TSENSOR_SETTINGS *tsettings) { // Apply new duty cycle if changed (with small tolerance to avoid constant updates) if (fabs(currentDuty - newDuty) > 0.1f) { pwmOut->setOutput(newDuty); - ESP_LOGI(tag, "Board T: %.2f F, Fan -> %.2f%% (on=%s)", temperature, newDuty, fanIsOn ? "true" : "false"); + ESP_LOGD(tag, "Board T: %.2f F, Fan -> %.2f%% (on=%s)", temperature, newDuty, fanIsOn ? "true" : "false"); } } diff --git a/src/my_wifi.cpp b/src/my_wifi.cpp index ec00a04..5cbef5c 100644 --- a/src/my_wifi.cpp +++ b/src/my_wifi.cpp @@ -1,30 +1,28 @@ #include "my_wifi.h" -#include -#include -#include +#include "AppUpgrade.h" +#include "common/fileSystem.h" +#include "esp_log.h" +#include "global.h" +#include "jsonconstrain.h" +#include "my_board.h" +#include "my_buzzer.h" +#include +#include #include #include -#include -#include "esp_log.h" #include #include #include -#include "common/fileSystem.h" -#include "global.h" -#include "my_buzzer.h" #include -#include -#include "jsonconstrain.h" -#include "AppUpgrade.h" -#include "my_board.h" +#include +#include +#include static const char *tag = "WIFI"; volatile bool InternetAvailable; AsyncWebServer webServer(80); AsyncEventSource eventUpgradeProgress("/upgrade-progress"); -// DNSServer *dnsServer; -// #define DNS_PORT 53 String client_ssid; String client_pass; @@ -39,10 +37,10 @@ IPAddress gateway(192, 168, 10, 1); IPAddress subnet(255, 255, 255, 0); // for file manager page -String filesDropdownOptions((char *)0); -String dirDropdownOptions((char *)0); -String savePath((char *)0); // needed for storing file when editing a file -String savePathInput((char *)0); +String filesDropdownOptions; +String dirDropdownOptions; +String savePath; // needed for storing file when editing a file +String savePathInput; const char *http_username = "admin"; const char *http_password = "12345678"; const char *param_delete_path = "delete-path"; @@ -67,11 +65,9 @@ static const uint8_t MAX_ATTEMPTS = 10; static SemaphoreHandle_t wifiMutex = nullptr; volatile bool wifi_task_running = false; -void Wifi_Init() -{ +void Wifi_Init() { // Initialize LittleFS - if (!LittleFS.begin(true)) - { + if (!LittleFS.begin(true)) { ESP_LOGE(tag, "LittleFS mount failed"); return; } @@ -86,8 +82,7 @@ void Wifi_Init() // Configure and start AP WiFi.softAPConfig(local_IP, gateway, subnet); - if (!WiFi.softAP(ap_ssid, ap_pass)) - { + if (!WiFi.softAP(ap_ssid, ap_pass)) { ESP_LOGE(tag, "AP start failed"); return; } @@ -109,12 +104,10 @@ void Wifi_Init() // Wifi_Scan_for_Networks(); } -void Wifi_Load_Settings(String path) -{ +void Wifi_Load_Settings(String path) { // Load WiFi settings File file = LittleFS.open(path, "r"); - if (!file) - { + if (!file) { ESP_LOGE(tag, "Error opening %s", path.c_str()); return; } @@ -123,49 +116,43 @@ void Wifi_Load_Settings(String path) DeserializationError error = deserializeJson(doc, file); file.close(); - if (error) - { + if (error) { ESP_LOGE(tag, "Failed to deserialize %s", path.c_str()); return; } JsonObject wifiJson = doc.as(); - if (wifiJson.isNull()) - { + if (wifiJson.isNull()) { ESP_LOGE(tag, "%s is empty", path.c_str()); return; } // Load AP settings JsonObject apJson = wifiJson["wifi-ap"]; - if (!apJson.isNull()) - { + if (!apJson.isNull()) { ap_ssid = jsonConstrainString(tag, apJson, "ssid", "ATA-AP"); ap_pass = jsonConstrainString(tag, apJson, "pass", "12345678"); local_IP.fromString(jsonConstrainString(tag, apJson, "ip", "192.168.10.1")); gateway.fromString(jsonConstrainString(tag, apJson, "gateway", "192.168.10.1")); subnet.fromString(jsonConstrainString(tag, apJson, "subnet", "255.255.255.0")); - char macSuffix[13] = {0}; // Just need 2 chars + null terminator + char macSuffix[13] = {0}; // Just need 2 chars + null terminator get_chip_mac(macSuffix, sizeof(macSuffix)); // Only get first 2 chars of MAC - ap_ssid += "-"; // Add a separator - ap_ssid += macSuffix[0]; // Add first character - ap_ssid += macSuffix[1]; // Add second character + ap_ssid += "-"; // Add a separator + ap_ssid += macSuffix[0]; // Add first character + ap_ssid += macSuffix[1]; // Add second character } // Load Client settings JsonObject clientJson = wifiJson["wifi-client"]; - if (!apJson.isNull()) - { + if (!apJson.isNull()) { client_ssid = jsonConstrainString(tag, clientJson, "ssid", "none"); client_pass = jsonConstrainString(tag, clientJson, "pass", "12345678"); } } -bool StartWifiConnectTask(String ssid = "", String pass = "") -{ - if (ssid.isEmpty() || pass.length() < 8) - { +bool StartWifiConnectTask(String ssid = "", String pass = "") { + if (ssid.isEmpty() || pass.length() < 8) { ESP_LOGE(tag, "Invalid SSID or password"); return false; } @@ -174,27 +161,22 @@ bool StartWifiConnectTask(String ssid = "", String pass = "") if (wifiMutex == nullptr) { wifiMutex = xSemaphoreCreateMutex(); } - + // Take mutex with timeout if (xSemaphoreTake(wifiMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { - if (!wifi_task_running) - { + if (!wifi_task_running) { client_ssid = ssid; client_pass = pass; - if (Wifi_Task_Handle == NULL) - { + if (Wifi_Task_Handle == NULL) { ESP_LOGI(tag, "Creating WiFi task"); - xTaskCreatePinnedToCore(Wifi_ConnectTask, "Wifi_Task", 1024 * 6, NULL, 1, &Wifi_Task_Handle, 0); + xTaskCreatePinnedToCore(Wifi_ConnectTask, "Wifi_Task", 1024 * 6, NULL, 1, + &Wifi_Task_Handle, 0); xSemaphoreGive(wifiMutex); return true; - } - else - { + } else { ESP_LOGI(tag, "WiFi task already running"); } - } - else - { + } else { ESP_LOGE(tag, "Task already running"); } xSemaphoreGive(wifiMutex); @@ -205,16 +187,14 @@ bool StartWifiConnectTask(String ssid = "", String pass = "") return false; } -void Wifi_ConnectTask(void *parameter) -{ +void Wifi_ConnectTask(void *parameter) { static const char *tag = "Wifi_Task"; wifi_task_running = true; - + // Register task with watchdog to prevent system hangs esp_task_wdt_add(NULL); - - if (WiFi.status() != WL_CONNECTED || client_ssid != WiFi.SSID()) - { + + if (WiFi.status() != WL_CONNECTED || client_ssid != WiFi.SSID()) { ESP_LOGI(tag, "Connecting to: %s", client_ssid.c_str()); // Disconnect and connect to new network @@ -224,13 +204,11 @@ void Wifi_ConnectTask(void *parameter) // Wait for connection uint8_t attempts = 0; - while (WiFi.status() != WL_CONNECTED && attempts < MAX_ATTEMPTS) - { + while (WiFi.status() != WL_CONNECTED && attempts < MAX_ATTEMPTS) { // Reset watchdog timer to prevent timeouts during connection attempts esp_task_wdt_reset(); - - switch (WiFi.status()) - { + + switch (WiFi.status()) { case WL_NO_SSID_AVAIL: ESP_LOGW(tag, "SSID not found: %s", client_ssid.c_str()); break; @@ -245,20 +223,16 @@ void Wifi_ConnectTask(void *parameter) } // Check if connected - if (WiFi.status() == WL_CONNECTED) - { + if (WiFi.status() == WL_CONNECTED) { ESP_LOGI(tag, "Connected to %s", client_ssid.c_str()); WiFi.setAutoReconnect(true); - if (!Wifi_Save_Credentials("/system/wifi.json")) - { + if (!Wifi_Save_Credentials("/system/wifi.json")) { ESP_LOGW(tag, "Failed to save credentials"); } Wifi_Check_Internet(); - } - else - { + } else { ESP_LOGE(tag, "Failed to connect after %d attempts", MAX_ATTEMPTS); } } @@ -267,20 +241,20 @@ void Wifi_ConnectTask(void *parameter) // Unregister from watchdog before deletion esp_task_wdt_delete(NULL); - + Wifi_Task_Handle = NULL; wifi_task_running = false; vTaskDelete(NULL); } -void Wifi_Check_Internet() -{ +void Wifi_Check_Internet() { // Check for internet connection with multiple fallback servers - const char *hosts[] = {"8.8.8.8", "1.1.1.1", "208.67.222.222"}; // Google DNS, Cloudflare DNS, OpenDNS + const char *hosts[] = {"8.8.8.8", "1.1.1.1", + "208.67.222.222"}; // Google DNS, Cloudflare DNS, OpenDNS const int num_hosts = sizeof(hosts) / sizeof(hosts[0]); - + InternetAvailable = false; - + // Try pinging each host for (int i = 0; i < num_hosts; i++) { if (Ping.ping(hosts[i], 1)) { @@ -291,23 +265,20 @@ void Wifi_Check_Internet() // Small delay between ping attempts vTaskDelay(pdMS_TO_TICKS(100)); } - + if (!InternetAvailable) { ESP_LOGW(tag, "No internet connection after trying multiple DNS servers"); } } -bool Wifi_Save_Credentials(String path) -{ +bool Wifi_Save_Credentials(String path) { // Load existing JSON JsonDocument doc; File readFile = LittleFS.open(path, "r"); - if (readFile) - { + if (readFile) { DeserializationError error = deserializeJson(doc, readFile); readFile.close(); - if (error) - { + if (error) { ESP_LOGE(tag, "Failed to parse existing JSON"); return false; } @@ -320,15 +291,13 @@ bool Wifi_Save_Credentials(String path) // Save updated JSON File writeFile = LittleFS.open(path, "w"); - if (!writeFile) - { + if (!writeFile) { ESP_LOGE(tag, "Error opening %s for writing", path.c_str()); return false; } // Serialize JSON with pretty formatting - if (serializeJsonPretty(doc, writeFile) == 0) - { + if (serializeJsonPretty(doc, writeFile) == 0) { ESP_LOGE(tag, "Failed to write JSON to file"); writeFile.close(); return false; @@ -340,14 +309,13 @@ bool Wifi_Save_Credentials(String path) /** * Scans for available WiFi networks and stores the results in JSON format - * + * * Updates scanStatus global: 0=none, 1=scanning, 2=complete, -1=error * Sets scanInProgress flag during operation * Populates networkList with JSON formatted scan results */ -void Wifi_Scan_for_Networks() -{ - static const char* tag = "WiFiScan"; +void Wifi_Scan_for_Networks() { + static const char *tag = "WiFiScan"; const uint32_t SCAN_TIMEOUT_MS = 15000; // 15 second timeout for scan // Protect against concurrent scans @@ -355,83 +323,101 @@ void Wifi_Scan_for_Networks() ESP_LOGW(tag, "WiFi scan already in progress"); return; } - + // Use mutex for thread safety if available bool useMutex = (wifiMutex != nullptr); if (useMutex && xSemaphoreTake(wifiMutex, pdMS_TO_TICKS(1000)) != pdTRUE) { ESP_LOGE(tag, "Failed to acquire mutex - WiFi operation in progress"); return; } - + scanInProgress = true; scanStatus = 1; // Scanning ESP_LOGI(tag, "Starting WiFi network scan"); - + // Start scan (async=false, show_hidden=false) WiFi.scanNetworks(false, false); - + // Wait for scan with timeout uint32_t startTime = millis(); - while (WiFi.scanComplete() == WIFI_SCAN_RUNNING) - { + while (WiFi.scanComplete() == WIFI_SCAN_RUNNING) { // Check for timeout if (millis() - startTime > SCAN_TIMEOUT_MS) { ESP_LOGE(tag, "WiFi scan timeout after %u ms", SCAN_TIMEOUT_MS); scanInProgress = false; scanStatus = -1; // Error - if (useMutex) xSemaphoreGive(wifiMutex); + if (useMutex) + xSemaphoreGive(wifiMutex); return; } - - // Reset watchdog if needed - #ifdef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0 + +// Reset watchdog if needed +#ifdef CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0 esp_task_wdt_reset(); - #endif - +#endif + vTaskDelay(pdMS_TO_TICKS(100)); // Wait for scan to complete } // Get scan results networkCount = WiFi.scanComplete(); - if (networkCount >= 0) - { + if (networkCount >= 0) { ESP_LOGI(tag, "WiFi scan complete, found %d networks", networkCount); scanStatus = 2; // Complete - + // Create JSON document with appropriate capacity JsonDocument doc; doc.clear(); JsonArray networks = doc["networks"].to(); - for (int i = 0; i < networkCount; i++) - { + for (int i = 0; i < networkCount; i++) { auto network = networks.add(); - + // Basic network info network["ssid"] = WiFi.SSID(i); network["rssi"] = WiFi.RSSI(i); network["channel"] = WiFi.channel(i); - + // Security details wifi_auth_mode_t encType = WiFi.encryptionType(i); network["encryption"] = encType != WIFI_AUTH_OPEN; - + // Add detailed encryption type - const char* encTypeStr = "unknown"; + const char *encTypeStr = "unknown"; switch (encType) { - case WIFI_AUTH_OPEN: encTypeStr = "open"; break; - case WIFI_AUTH_WEP: encTypeStr = "WEP"; break; - case WIFI_AUTH_WPA_PSK: encTypeStr = "WPA_PSK"; break; - case WIFI_AUTH_WPA2_PSK: encTypeStr = "WPA2_PSK"; break; - case WIFI_AUTH_WPA_WPA2_PSK: encTypeStr = "WPA_WPA2_PSK"; break; - case WIFI_AUTH_WPA2_ENTERPRISE: encTypeStr = "WPA2_ENTERPRISE"; break; - case WIFI_AUTH_WPA3_PSK: encTypeStr = "WPA3_PSK"; break; - case WIFI_AUTH_WPA2_WPA3_PSK: encTypeStr = "WPA2_WPA3_PSK"; break; - case WIFI_AUTH_WAPI_PSK: encTypeStr = "WAPI_PSK"; break; - default: encTypeStr = "unknown"; break; + case WIFI_AUTH_OPEN: + encTypeStr = "open"; + break; + case WIFI_AUTH_WEP: + encTypeStr = "WEP"; + break; + case WIFI_AUTH_WPA_PSK: + encTypeStr = "WPA_PSK"; + break; + case WIFI_AUTH_WPA2_PSK: + encTypeStr = "WPA2_PSK"; + break; + case WIFI_AUTH_WPA_WPA2_PSK: + encTypeStr = "WPA_WPA2_PSK"; + break; + case WIFI_AUTH_WPA2_ENTERPRISE: + encTypeStr = "WPA2_ENTERPRISE"; + break; + case WIFI_AUTH_WPA3_PSK: + encTypeStr = "WPA3_PSK"; + break; + case WIFI_AUTH_WPA2_WPA3_PSK: + encTypeStr = "WPA2_WPA3_PSK"; + break; + case WIFI_AUTH_WAPI_PSK: + encTypeStr = "WAPI_PSK"; + break; + default: + encTypeStr = "unknown"; + break; } network["security"] = encTypeStr; - + // Add signal quality 0-100% int rssi = WiFi.RSSI(i); int rssiLimited = rssi < -100 ? -100 : (rssi > -50 ? -50 : rssi); @@ -442,267 +428,295 @@ void Wifi_Scan_for_Networks() // Serialize to the global variable networkList.clear(); serializeJson(doc, networkList); - + // Clean up scan results from memory WiFi.scanDelete(); - } - else - { + } else { ESP_LOGE(tag, "WiFi scan failed with error code: %d", networkCount); scanStatus = -1; // Error } - + scanInProgress = false; - if (useMutex) xSemaphoreGive(wifiMutex); + if (useMutex) + xSemaphoreGive(wifiMutex); } -void Setup_WebServer_Handlers(AsyncWebServer &server) -{ +void Setup_WebServer_Handlers(AsyncWebServer &server) { - server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) - { request->send(LittleFS, "/www/index.html", "text/html"); }); - server.on("/home", HTTP_GET, [](AsyncWebServerRequest *request) - { sendHtmlFile("/www/home.html", request, HomeHtmlProcessor); }); - server.on("/setup", HTTP_GET, [](AsyncWebServerRequest *request) - { - if (!request->authenticate(http_username, http_password)) - { - return request->requestAuthentication(); - } - // sendHtmlFile("/www/setup.html", request, htmlProcessor); - }); - server.on("/about", HTTP_GET, [](AsyncWebServerRequest *request) - { - sendHtmlFile("/www/about.html", request, fileManagerHtmlProcessor); - // request->send(LittleFS, "/www/about.html", "text/html"); - }); + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(LittleFS, "/www/index.html", "text/html"); + }); + server.on("/home", HTTP_GET, [](AsyncWebServerRequest *request) { + sendHtmlFile("/www/home.html", request, HomeHtmlProcessor); + }); + server.on("/setup", HTTP_GET, [](AsyncWebServerRequest *request) { + if (!request->authenticate(http_username, http_password)) { + return request->requestAuthentication(); + } + // sendHtmlFile("/www/setup.html", request, htmlProcessor); + }); + server.on("/about", HTTP_GET, [](AsyncWebServerRequest *request) { + sendHtmlFile("/www/about.html", request, fileManagerHtmlProcessor); + // request->send(LittleFS, "/www/about.html", "text/html"); + }); // Wifi related handlers - server.on("/wifi/connect", HTTP_POST, [](AsyncWebServerRequest *request) - { - // Input validation - if (!request->hasParam("ssid", false, false) || !request->hasParam("pass", false, false)) { - ESP_LOGE(tag, "Missing required parameters"); - request->send(400, "application/json", "{\"error\":\"Missing ssid or password\"}"); - return; - } + server.on("/wifi/connect", HTTP_POST, [](AsyncWebServerRequest *request) { + // Input validation + if (!request->hasParam("ssid", false, false) || !request->hasParam("pass", false, false)) { + ESP_LOGE(tag, "Missing required parameters"); + request->send(400, "application/json", "{\"error\":\"Missing ssid or password\"}"); + return; + } - // Get and store credentials - String ssid = request->getParam("ssid", false, false)->value(); - String pass = request->getParam("pass", false, false)->value(); + // Get and store credentials + String ssid = request->getParam("ssid", false, false)->value(); + String pass = request->getParam("pass", false, false)->value(); - // Validate credentials - if (ssid.length() < 1 || pass.length() < 8) { - ESP_LOGE(tag, "Invalid credentials"); - request->send(400, "application/json", "{\"error\":\"Invalid credentials\"}"); - return; - } + // Validate credentials + if (ssid.length() < 1 || pass.length() < 8) { + ESP_LOGE(tag, "Invalid credentials"); + request->send(400, "application/json", "{\"error\":\"Invalid credentials\"}"); + return; + } - // Start connection - StartWifiConnectTask(ssid, pass); - - ESP_LOGI(tag, "Starting connection to %s", client_ssid.c_str()); - request->send(200, "application/json", "{\"status\":\"connecting\"}"); }); - server.on("/wifi/status", HTTP_GET, [](AsyncWebServerRequest *request) - { - String jsonStr = "{\"status\":\"" + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + - "\",\"ip\":\"" + WiFi.localIP().toString() + "\"}"; - request->send(200, "application/json", jsonStr); }); - server.on("/wifi/scans", HTTP_GET, [](AsyncWebServerRequest *request) - { - if(networkCount <= 0) { - request->send(400, "application/json", "{\"error\":\"No scan results\"}"); - return; - } - - request->send(200, "application/json", networkList); }); - server.on("/wifi", HTTP_GET, [](AsyncWebServerRequest *request) - { - if(WiFi.getMode() == WIFI_MODE_APSTA){ - // TODO Disable navigation bar - } - //sendHtmlFile("/www/wifi.html", request, htmlProcessor); - request->send(LittleFS, "/www/wifi.html", "text/html"); }); + // Start connection + StartWifiConnectTask(ssid, pass); + + ESP_LOGI(tag, "Starting connection to %s", client_ssid.c_str()); + request->send(200, "application/json", "{\"status\":\"connecting\"}"); + }); + server.on("/wifi/status", HTTP_GET, [](AsyncWebServerRequest *request) { + String jsonStr = "{\"status\":\"" + + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + + "\",\"ip\":\"" + WiFi.localIP().toString() + "\"}"; + request->send(200, "application/json", jsonStr); + }); + server.on("/wifi/scans", HTTP_GET, [](AsyncWebServerRequest *request) { + if (networkCount <= 0) { + request->send(400, "application/json", "{\"error\":\"No scan results\"}"); + return; + } + + request->send(200, "application/json", networkList); + }); + server.on("/wifi", HTTP_GET, [](AsyncWebServerRequest *request) { + if (WiFi.getMode() == WIFI_MODE_APSTA) { + // TODO Disable navigation bar + } + // sendHtmlFile("/www/wifi.html", request, htmlProcessor); + request->send(LittleFS, "/www/wifi.html", "text/html"); + }); // File Manager related handlers - server.on("/files/upload", HTTP_POST, [](AsyncWebServerRequest *request) - { request->send(200); }, handleFilesUpload_OnBody); + server.on( + "/files/upload", HTTP_POST, [](AsyncWebServerRequest *request) { request->send(200); }, + handleFilesUpload_OnBody); - server.on("/files/download", HTTP_GET, [](AsyncWebServerRequest *request) - { - if (!request->hasParam("file")) { - ESP_LOGE(tag, "Missing file parameter"); - request->send(400, "text/plain", "Missing file parameter"); - return; - } + server.on("/files/download", HTTP_GET, [](AsyncWebServerRequest *request) { + if (!request->hasParam("file")) { + ESP_LOGE(tag, "Missing file parameter"); + request->send(400, "text/plain", "Missing file parameter"); + return; + } - try { String filename = uriDecode(request->getParam("file")->value()); + // Prevent directory traversal + if (filename.indexOf("..") >= 0) { + ESP_LOGW(tag, "Rejected download with unsafe path: %s", filename.c_str()); + request->send(400, "text/plain", "Invalid file path"); + return; + } + if (!filename.startsWith("/")) filename = "/" + filename; + + if (!LittleFS.exists(filename)) { + ESP_LOGE(tag, "File not found: %s", filename.c_str()); + request->send(404, "text/plain", "File not found!"); + return; + } + ESP_LOGI(tag, "Download request for: %s", filename.c_str()); request->send(LittleFS, filename, "application/octet-stream"); - } - catch (const std::exception& e) { - ESP_LOGE(tag, "Download failed: %s", e.what()); - request->send(404, "text/plain", "File not found!"); - } }); - server.on("/files/delete", HTTP_GET, [](AsyncWebServerRequest *request) - { - static const char* tag = "DeleteHandler"; + }); + server.on("/files/delete", HTTP_GET, [](AsyncWebServerRequest *request) { + static const char *tag = "DeleteHandler"; - // Authentication check - if (!request->authenticate(http_username, http_password)) { - ESP_LOGW(tag, "Authentication failed for delete request"); - return request->requestAuthentication(); - } + // Authentication check + if (!request->authenticate(http_username, http_password)) { + ESP_LOGW(tag, "Authentication failed for delete request"); + return request->requestAuthentication(); + } - // Parameter validation - if (!request->hasParam(param_delete_path)) { - ESP_LOGE(tag, "Missing delete path parameter"); - request->send(400, "text/plain", "Missing file path"); - return; - } + // Parameter validation + if (!request->hasParam(param_delete_path)) { + ESP_LOGE(tag, "Missing delete path parameter"); + request->send(400, "text/plain", "Missing file path"); + return; + } - // Get and validate filename - String filename = uriDecode(request->getParam(param_delete_path)->value()); - if (filename == "choose") { - request->redirect("/files"); - return; - } + // Get and validate filename + String filename = uriDecode(request->getParam(param_delete_path)->value()); + if (filename == "choose") { + request->redirect("/files"); + return; + } - // Ensure path starts with / - if (!filename.startsWith("/")) { - filename = "/" + filename; - } + // Prevent directory traversal + if (filename.indexOf("..") >= 0) { + ESP_LOGW(tag, "Rejected delete with unsafe path: %s", filename.c_str()); + request->send(400, "text/plain", "Invalid file path"); + return; + } - try { - if (LittleFS.remove(filename.c_str())) { - ESP_LOGI(tag, "Successfully deleted file: %s", filename.c_str()); - } else { - ESP_LOGE(tag, "Failed to delete file: %s", filename.c_str()); - request->send(500, "text/plain", "Delete failed"); - return; - } - } catch (const std::exception& e) { - ESP_LOGE(tag, "Exception during delete: %s", e.what()); - request->send(500, "text/plain", "Delete failed"); - return; - } + // Ensure path starts with / + if (!filename.startsWith("/")) filename = "/" + filename; + while (filename.indexOf("//") >= 0) filename.replace("//", "/"); - request->redirect("/files"); }); - server.on("/files/edit", HTTP_GET, [](AsyncWebServerRequest *request) - { - static const char* tag = "EditHandler"; + if (LittleFS.remove(filename.c_str())) { + ESP_LOGI(tag, "Successfully deleted file: %s", filename.c_str()); + } else { + ESP_LOGE(tag, "Failed to delete file: %s", filename.c_str()); + request->send(500, "text/plain", "Delete failed"); + return; + } - // Authentication check - if (!request->authenticate(http_username, http_password)) { - ESP_LOGW(tag, "Authentication failed"); - return request->requestAuthentication(); - } + request->redirect("/files"); + }); + server.on("/files/edit", HTTP_GET, [](AsyncWebServerRequest *request) { + static const char *tag = "EditHandler"; - // Parameter validation - if (!request->hasParam(param_edit_path)) { - ESP_LOGE(tag, "Missing edit path parameter"); - request->send(400, "text/plain", "Missing file path"); - return; - } + // Authentication check + if (!request->authenticate(http_username, http_password)) { + ESP_LOGW(tag, "Authentication failed"); + return request->requestAuthentication(); + } - // Get and decode filename - String fileName = uriDecode(request->getParam(param_edit_path)->value()); - ESP_LOGI(tag, "Edit request for file: %s", fileName.c_str()); + // Parameter validation + if (!request->hasParam(param_edit_path)) { + ESP_LOGE(tag, "Missing edit path parameter"); + request->send(400, "text/plain", "Missing file path"); + return; + } - // Set save path - savePath = (fileName == "new") ? "/new.txt" : fileName; + // Get and decode filename + String fileName = uriDecode(request->getParam(param_edit_path)->value()); + ESP_LOGI(tag, "Edit request for file: %s", fileName.c_str()); - // Validate path - if (!savePath.startsWith("/")) { - savePath = "/" + savePath; - } + // Set save path + savePath = (fileName == "new") ? "/new.txt" : fileName; - ESP_LOGI(tag, "Save path set to: %s", savePath.c_str()); - - try { - sendHtmlFile("/www/edit.html", request, fileManagerHtmlProcessor); - } catch (const std::exception& e) { - ESP_LOGE(tag, "Failed to send edit page: %s", e.what()); - request->send(500, "text/plain", "Internal server error"); - } }); - server.on("/files/save", HTTP_GET, [](AsyncWebServerRequest *request) - { - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - String inputMessage((char*)0); - if (request->hasParam(param_edit_textarea)) { - inputMessage = request->getParam(param_edit_textarea)->value(); - } - if (request->hasParam(param_save_path)) { - savePath = uriDecode(request->getParam(param_save_path)->value()); - } - writeFile(LittleFS, savePath.c_str(), inputMessage.c_str()); + // Validate path + if (!savePath.startsWith("/")) { + savePath = "/" + savePath; + } - request->redirect("/files"); }); - server.on("/files", HTTP_GET, [](AsyncWebServerRequest *request) - { - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - sendHtmlFile("/www/files.html", request, fileManagerHtmlProcessor); }); + ESP_LOGI(tag, "Save path set to: %s", savePath.c_str()); + + if (!sendHtmlFile("/www/edit.html", request, fileManagerHtmlProcessor)) { + ESP_LOGE(tag, "Failed to send edit page: %s", "/www/edit.html"); + request->send(500, "text/plain", "Internal server error"); + } + }); + server.on("/files/save", HTTP_GET, [](AsyncWebServerRequest *request) { + if (!request->authenticate(http_username, http_password)) { + return request->requestAuthentication(); + } + String inputMessage; + if (request->hasParam(param_edit_textarea)) { + inputMessage = request->getParam(param_edit_textarea)->value(); + } + if (request->hasParam(param_save_path)) { + savePath = uriDecode(request->getParam(param_save_path)->value()); + if (savePath.indexOf("..") >= 0) { + ESP_LOGW(tag, "Rejected save with unsafe path: %s", savePath.c_str()); + request->send(400, "text/plain", "Invalid file path"); + return; + } + if (!savePath.startsWith("/")) savePath = "/" + savePath; + while (savePath.indexOf("//") >= 0) savePath.replace("//", "/"); + } + writeFile(LittleFS, savePath.c_str(), inputMessage.c_str()); + + request->redirect("/files"); + }); + server.on("/files", HTTP_GET, [](AsyncWebServerRequest *request) { + if (!request->authenticate(http_username, http_password)) { + return request->requestAuthentication(); + } + sendHtmlFile("/www/files.html", request, fileManagerHtmlProcessor); + }); // Lights related handlers - server.on("/lights/settings", HTTP_GET, [](AsyncWebServerRequest *request) - { request->send(200); }); - server.on("/lights/settings", HTTP_POST, [](AsyncWebServerRequest *request) - { request->send(200); }); - server.on("/lights/animation", HTTP_POST, [](AsyncWebServerRequest *request) - { request->send(200); }); - server.on("/lights/setpixel", HTTP_POST, [](AsyncWebServerRequest *request) - { request->send(200); }); + server.on("/lights/settings", HTTP_GET, + [](AsyncWebServerRequest *request) { request->send(200); }); + server.on("/lights/settings", HTTP_POST, + [](AsyncWebServerRequest *request) { request->send(200); }); + server.on("/lights/animation", HTTP_POST, + [](AsyncWebServerRequest *request) { request->send(200); }); + server.on("/lights/setpixel", HTTP_POST, + [](AsyncWebServerRequest *request) { request->send(200); }); // System and LED related handlers - server.on("/system/summary", HTTP_GET, [](AsyncWebServerRequest *request) - { - String response = "{\"status\":\"" + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + "\"}"; - request->send(200, "application/json", response); }); - server.on("/leds/settings", HTTP_GET, [](AsyncWebServerRequest *request) - { - /* - //CreateSysSummmaryPacket(doc); - String summary; - serializeJson(jsDoc, summary); - request->send(200, "application/json", summary); - */ - String response = "{\"status\":\"" + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + "\"}"; - request->send(200, "application/json", response); }); - server.on("/leds/settings", HTTP_POST, [](AsyncWebServerRequest *request) - { - String response = "{\"status\":\"" + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + "\"}"; - request->send(200, "application/json", response); }); + server.on("/system/summary", HTTP_GET, [](AsyncWebServerRequest *request) { + String response = "{\"status\":\"" + + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + + "\"}"; + request->send(200, "application/json", response); + }); + server.on("/leds/settings", HTTP_GET, [](AsyncWebServerRequest *request) { + /* + //CreateSysSummmaryPacket(doc); + String summary; + serializeJson(jsDoc, summary); + request->send(200, "application/json", summary); + */ + String response = "{\"status\":\"" + + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + + "\"}"; + request->send(200, "application/json", response); + }); + server.on("/leds/settings", HTTP_POST, [](AsyncWebServerRequest *request) { + String response = "{\"status\":\"" + + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + + "\"}"; + request->send(200, "application/json", response); + }); // LightStik related handlers - server.on("/lightstik/settings", HTTP_GET, [](AsyncWebServerRequest *request) - { - String response = "{\"status\":\"" + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + "\"}"; - request->send(200, "application/json", response); }); - server.on("/lightstik/settings", HTTP_POST, [](AsyncWebServerRequest *request) - { - String response = "{\"status\":\"" + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + "\"}"; - request->send(200, "application/json", response); }); - server.on("/lightstik/register", HTTP_POST, [](AsyncWebServerRequest *request) - { - String response = "{\"status\":\"" + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + "\"}"; - request->send(200, "application/json", response); }); + server.on("/lightstik/settings", HTTP_GET, [](AsyncWebServerRequest *request) { + String response = "{\"status\":\"" + + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + + "\"}"; + request->send(200, "application/json", response); + }); + server.on("/lightstik/settings", HTTP_POST, [](AsyncWebServerRequest *request) { + String response = "{\"status\":\"" + + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + + "\"}"; + request->send(200, "application/json", response); + }); + server.on("/lightstik/register", HTTP_POST, [](AsyncWebServerRequest *request) { + String response = "{\"status\":\"" + + String(WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected") + + "\"}"; + request->send(200, "application/json", response); + }); // Firmware Update Handlers - server.on("/upgrade/check", HTTP_GET, [](AsyncWebServerRequest *request) - { + server.on("/upgrade/check", HTTP_GET, [](AsyncWebServerRequest *request) { // Ensure updateUrl is loaded (function resides in AppUpgrade.cpp) - loadUpdateJson(); - // Pass nullptr bucket to use internally loaded default + subsequently set base via setBaseUrl if needed + if (!loadUpdateJson()) { + ESP_LOGE(tag, "Failed to load update.json for /upgrade/check"); + } + // Pass nullptr bucket to use internally loaded default + subsequently set base via + // setBaseUrl if needed AppUpdater updater(LittleFS, localVersion, nullptr, "update.json", "firmware.bin"); // If a dynamic URL was loaded, override base extern String updateUrl; // declared in AppUpgrade.cpp - if(updateUrl.length()) updater.setBaseUrl(updateUrl); - // checkManifest() does not return a bool; capture its result (type-dependent) instead of using it in a boolean expression + if (updateUrl.length()) + updater.setBaseUrl(updateUrl); + // checkManifest() does not return a bool; capture its result (type-dependent) instead of + // using it in a boolean expression auto manifestResult = updater.checkManifest(); // TODO: inspect manifestResult for success/failure once its API is known otaVersion = updater.otaVersion; @@ -710,120 +724,115 @@ void Setup_WebServer_Handlers(AsyncWebServer &server) JsonDocument doc; doc["currentVersion"] = localVersion.toString(); - doc["latestVersion"] = otaVersion.toString(); + doc["latestVersion"] = otaVersion.toString(); doc["updateAvailable"] = avail; - + String response; serializeJson(doc, response); - request->send(200, "application/json", response); }); + request->send(200, "application/json", response); + }); // Start update process - server.on("/upgrade/start", HTTP_POST, [](AsyncWebServerRequest *request) - { - startFirmwareUpdateTask(&eventUpgradeProgress); - request->send(200); }); - eventUpgradeProgress.onConnect([](AsyncEventSourceClient *client) - { - if (client->lastId()) - { - Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId()); - } - // send event with message "hello!", id current millis - // and set reconnect delay to 1 second - // client->send("hello!", NULL, millis(), 10000); - }); - server.on("/upgrade", HTTP_GET, [](AsyncWebServerRequest *request) - { - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - request->send(LittleFS, "/www/upgrade.html", "text/html"); }); + server.on("/upgrade/start", HTTP_POST, [](AsyncWebServerRequest *request) { + startFirmwareUpdateTask(&eventUpgradeProgress); + request->send(200); + }); + eventUpgradeProgress.onConnect([](AsyncEventSourceClient *client) { + if (client->lastId()) { + Serial.printf("Client reconnected! Last message ID that it got is: %u\n", + client->lastId()); + } + // send event with message "hello!", id current millis + // and set reconnect delay to 1 second + // client->send("hello!", NULL, millis(), 10000); + }); + server.on("/upgrade", HTTP_GET, [](AsyncWebServerRequest *request) { + if (!request->authenticate(http_username, http_password)) { + return request->requestAuthentication(); + } + request->send(LittleFS, "/www/upgrade.html", "text/html"); + }); server.addHandler(&eventUpgradeProgress); // Basic Connection status check - server.on("/api/status", HTTP_GET, [](AsyncWebServerRequest *request) - { request->send(200, "application/json", "{\"status\":\"connected\"}"); }); + server.on("/api/status", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "application/json", "{\"status\":\"connected\"}"); + }); // Server requested files that aren't template processed server.on("/*", HTTP_GET, [](AsyncWebServerRequest *request) { // handle file uploads // Validate request - if (!request) - { + if (!request) { ESP_LOGE(tag, "Invalid request"); return; } // Get and validate file path String filePath = request->url(); - if (filePath.isEmpty()) - { + if (filePath.isEmpty()) { ESP_LOGE(tag, "Empty file path"); request->send(400, "text/plain", "Invalid file path"); return; } // Ensure path starts with '/' - if (!filePath.startsWith("/")) - { + if (!filePath.startsWith("/")) { filePath = "/" + filePath; } - try - { - // Get content type once - const char *contentType = getFileType(getFileExtension(filePath.c_str())); - if (!contentType) - { - ESP_LOGW(tag, "Unknown file type: %s", filePath.c_str()); - contentType = "application/octet-stream"; - } + // Basic sanitization to prevent directory traversal + if (filePath.indexOf("..") >= 0) { + ESP_LOGW(tag, "Rejected unsafe path: %s", filePath.c_str()); + request->send(400, "text/plain", "Invalid file path"); + return; + } - ESP_LOGI(tag, "Sending file: %s (%s)", filePath.c_str(), contentType); - request->send(LittleFS, filePath, contentType); - } - catch (const std::runtime_error &e) - { - ESP_LOGE(tag, "FileSystem error: %s for path: %s", e.what(), filePath.c_str()); - request->send(404, "text/plain", "File not found"); - } - catch (const std::exception &e) - { - ESP_LOGE(tag, "Error: %s for path: %s", e.what(), filePath.c_str()); - request->send(500, "text/plain", "Internal server error"); + // Ensure leading slash and collapse duplicate slashes + if (!filePath.startsWith("/")) filePath = "/" + filePath; + while (filePath.indexOf("//") >= 0) filePath.replace("//", "/"); + + // Get content type once + const char *contentType = getFileType(getFileExtension(filePath.c_str())); + if (!contentType) { + ESP_LOGW(tag, "Unknown file type: %s", filePath.c_str()); + contentType = "application/octet-stream"; } + + ESP_LOGD(tag, "Sending file: %s (%s)", filePath.c_str(), contentType); + request->send(LittleFS, filePath, contentType); }); // 404 handler - server.onNotFound([](AsyncWebServerRequest *request) - { - ESP_LOGE(tag, "404: %s", request->url().c_str()); - request->send(404, "text/plain", "Not found"); }); + server.onNotFound([](AsyncWebServerRequest *request) { + ESP_LOGE(tag, "404: %s", request->url().c_str()); + request->send(404, "text/plain", "Not found"); + }); } -void handleFilesUpload_OnBody(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) -{ +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 - if (!index) - { + if (!index) { // Initial upload chunk - if (!request->hasParam("dir-path", true, false)) - { + 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 path = p->value() + "/" + filename; - ESP_LOGI(tag, "Starting upload: %s", path.c_str()); + String path = p->value() + "/" + filename; + // Normalize and reject traversal + if (path.indexOf("..") >= 0) { + ESP_LOGW(tag, "Rejected upload with unsafe path: %s", path.c_str()); + request->send(400, "text/plain", "Invalid upload path"); + return; + } + if (!path.startsWith("/")) path = "/" + path; + while (path.indexOf("//") >= 0) path.replace("//", "/"); - // Validate path - if (!path.startsWith("/")) - { - path = "/" + path; - } + ESP_LOGI(tag, "Starting upload: %s", path.c_str()); - request->_tempFile = LittleFS.open(path, "w"); - if (!request->_tempFile) - { + 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; @@ -831,10 +840,8 @@ void handleFilesUpload_OnBody(AsyncWebServerRequest *request, String filename, s } // Write chunk - if (len && request->_tempFile) - { - if (index + len > MAX_UPLOAD_SIZE) - { + if (len && request->_tempFile) { + if (index + len > MAX_UPLOAD_SIZE) { request->_tempFile.close(); LittleFS.remove(request->_tempFile.name()); ESP_LOGE(tag, "Upload too large"); @@ -842,8 +849,7 @@ void handleFilesUpload_OnBody(AsyncWebServerRequest *request, String filename, s return; } - if (!request->_tempFile.write(data, len)) - { + if (!request->_tempFile.write(data, len)) { ESP_LOGE(tag, "Write failed"); request->_tempFile.close(); request->send(500, "text/plain", "Write failed"); @@ -851,8 +857,7 @@ void handleFilesUpload_OnBody(AsyncWebServerRequest *request, String filename, s } } - if (final) - { + if (final) { request->_tempFile.close(); ESP_LOGI(tag, "Upload complete: %s, %u bytes", filename.c_str(), index + len); request->redirect("/files"); @@ -860,58 +865,46 @@ void handleFilesUpload_OnBody(AsyncWebServerRequest *request, String filename, s } // Send html file with template processing {{VAR}} -void sendHtmlFile(const char *filePath, AsyncWebServerRequest *request, String (*callback)(const String &)) -{ - try - { - const char *htmlFile = readFile(LittleFS, filePath); - if (!htmlFile) - { - ESP_LOGE(tag, "Failed to read file: %s", filePath); - request->send(404, "text/plain", "File not found"); - return; - } - - String processedData = varReplace(htmlFile, callback); - delete[] htmlFile; // Clean up allocated memory - - ESP_LOGI(tag, "Sent file: %s", filePath); - request->send(200, "text/html", processedData); - } - catch (const std::exception &e) - { - ESP_LOGE(tag, "Error processing file %s: %s", filePath, e.what()); - request->send(500, "text/plain", "Server error"); +bool sendHtmlFile(const char *filePath, AsyncWebServerRequest *request, + String (*callback)(const String &)) { + const char *htmlFile = readFile(LittleFS, filePath); + if (!htmlFile) { + ESP_LOGE(tag, "Failed to read file: %s", filePath); + request->send(404, "text/plain", "File not found"); + return false; } + + String processedData = varReplace(htmlFile, callback); + delete[] htmlFile; // Clean up allocated memory + + ESP_LOGI(tag, "Sent file: %s", filePath); + request->send(200, "text/html", processedData); + return true; } -const char *getFileExtension(const char *filename) -{ +const char *getFileExtension(const char *filename) { // Input validation - if (!filename) - { + if (!filename) { ESP_LOGW(tag, "Null filename provided"); return ""; } // Find last dot const char *lastDot = strrchr(filename, '.'); - if (!lastDot || lastDot == filename || *(lastDot + 1) == '\0') - { - ESP_LOGI(tag, "No valid extension found in: %s", filename); + if (!lastDot || lastDot == filename || *(lastDot + 1) == '\0') { + ESP_LOGD(tag, "No valid extension found in: %s", filename); return ""; } - ESP_LOGI(tag, "Found extension: %s", lastDot + 1); + ESP_LOGD(tag, "Found extension: %s", lastDot + 1); return lastDot + 1; } -const char *getFileType(const char *ext) -{ +const char *getFileType(const char *ext) { if (!ext) return "application/octet-stream"; - ESP_LOGI(tag, "Getting file type for extension: %s", ext); + ESP_LOGD(tag, "Getting file type for extension: %s", ext); if (strcmp(ext, "png") == 0) return "image/png"; @@ -932,18 +925,16 @@ const char *getFileType(const char *ext) if (strcmp(ext, "json") == 0) return "application/json"; - ESP_LOGW(tag, "Unknown file extension: %s", ext); + ESP_LOGD(tag, "Unknown file extension: %s", ext); return "application/octet-stream"; } // Finds segments between {{VAR}} and calls a callback function to replace VAR with new content -String varReplace(const String &input, String (*callback)(const String &)) -{ +String varReplace(const String &input, String (*callback)(const String &)) { static const char *tag = "varReplace"; // Validate inputs - if (input.isEmpty() || !callback) - { + if (input.isEmpty() || !callback) { ESP_LOGW(tag, "Empty input or null callback"); return input; } @@ -956,12 +947,10 @@ String varReplace(const String &input, String (*callback)(const String &)) int startPos = 0; // Process all segments - while (true) - { + while (true) { // Find next variable int start = input.indexOf("{{", startPos); - if (start == -1) - { + if (start == -1) { break; } @@ -970,8 +959,7 @@ String varReplace(const String &input, String (*callback)(const String &)) // Find end of variable int end = input.indexOf("}}", start + 2); - if (end == -1) - { + if (end == -1) { ESP_LOGW(tag, "Unmatched {{ at position %d", start); result += input.substring(start); break; @@ -979,21 +967,15 @@ String varReplace(const String &input, String (*callback)(const String &)) // Extract and validate segment String segment = input.substring(start + 2, end); - if (segment.length() <= maxSegmentLength) - { - try - { - String replacement = callback(segment); + if (segment.length() <= maxSegmentLength) { + String replacement = callback(segment); + if (!replacement.isEmpty()) { result += replacement; - } - catch (const std::exception &e) - { - ESP_LOGE(tag, "Callback error: %s", e.what()); + } else { + ESP_LOGW(tag, "Callback returned empty for segment: %s", segment.c_str()); result += input.substring(start, end + 2); } - } - else - { + } else { ESP_LOGW(tag, "Segment too long: %d chars", segment.length()); result += input.substring(start, end + 2); } @@ -1002,43 +984,33 @@ String varReplace(const String &input, String (*callback)(const String &)) } // Add remaining text - if (startPos < input.length()) - { + if (startPos < input.length()) { result += input.substring(startPos); } return result; } -const char *convertFileSize(const size_t bytes) -{ +const char *convertFileSize(const size_t bytes) { static char fileSizeBuffer[16]; // Pre-allocated buffer for the file size - if (bytes < 1024) - { + if (bytes < 1024) { snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%d B", bytes); - } - else if (bytes < 1024 * 1024) - { + } else if (bytes < 1024 * 1024) { snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%.2f kB", bytes / 1024.0); - } - else if (bytes < 1024 * 1024 * 1024) - { + } else if (bytes < 1024 * 1024 * 1024) { snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%.2f MB", bytes / (1024.0 * 1024.0)); - } - else - { - snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%.2f GB", bytes / (1024.0 * 1024.0 * 1024.0)); + } else { + snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%.2f GB", + bytes / (1024.0 * 1024.0 * 1024.0)); } return fileSizeBuffer; } -void onWiFiEvent(WiFiEvent_t event) -{ +void onWiFiEvent(WiFiEvent_t event) { // Serial.printf("[WiFi-event] event: %d\n", event); - switch (event) - { + switch (event) { case ARDUINO_EVENT_WIFI_READY: ESP_LOGI(tag, "WiFi interface ready"); break; @@ -1132,51 +1104,41 @@ void onWiFiEvent(WiFiEvent_t event) } } -void Wifi_Start_MDNS(void) -{ +void Wifi_Start_MDNS(void) { ESP_LOGV(tag, "Initializing MDNS: %s", mDnsName.c_str()); - if (!MDNS.begin(mDnsName.c_str())) - { + if (!MDNS.begin(mDnsName.c_str())) { ESP_LOGE(tag, "Error setting up MDNS responder!"); - } - else - { + } else { 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 - if (!path || !message) - { + if (!path || !message) { ESP_LOGE(tag, "Invalid parameters: path=%p message=%p", path, message); return false; } // Normalize and validate path String finalPath(path); - if (!finalPath.startsWith("/")) - { + if (!finalPath.startsWith("/")) { finalPath = String("/") + finalPath; } // Prevent directory traversal - if (finalPath.indexOf("..") >= 0) - { + if (finalPath.indexOf("..") >= 0) { ESP_LOGE(tag, "Rejected unsafe path: %s", finalPath.c_str()); return false; } // Collapse duplicate slashes (optional hardening) - while (finalPath.indexOf("//") >= 0) - { + while (finalPath.indexOf("//") >= 0) { finalPath.replace("//", "/"); } // Size checks const size_t MAX_FILE_SIZE = 1024 * 1024; // 1MB cap (aligned with readFile) const size_t totalSize = strlen(message); - if (totalSize > MAX_FILE_SIZE) - { + if (totalSize > MAX_FILE_SIZE) { ESP_LOGE(tag, "Write too large: %u bytes for %s", (unsigned)totalSize, finalPath.c_str()); return false; } @@ -1184,8 +1146,7 @@ bool writeFile(fs::FS &fs, const char *path, const char *message) // Write to a temporary file first for atomicity String tmpPath = finalPath + ".tmp"; File tmp = fs.open(tmpPath.c_str(), "w"); - if (!tmp) - { + if (!tmp) { ESP_LOGE(tag, "Failed to open temp file: %s", tmpPath.c_str()); return false; } @@ -1193,12 +1154,11 @@ bool writeFile(fs::FS &fs, const char *path, const char *message) // Write in a loop to ensure all bytes are written size_t written = 0; const uint8_t *buf = reinterpret_cast(message); - while (written < totalSize) - { + while (written < totalSize) { size_t n = tmp.write(buf + written, totalSize - written); - if (n == 0) - { - ESP_LOGE(tag, "Write failed to temp file: %s at %u/%u bytes", tmpPath.c_str(), (unsigned)written, (unsigned)totalSize); + if (n == 0) { + ESP_LOGE(tag, "Write failed to temp file: %s at %u/%u bytes", tmpPath.c_str(), + (unsigned)written, (unsigned)totalSize); tmp.close(); fs.remove(tmpPath.c_str()); return false; @@ -1211,17 +1171,14 @@ bool writeFile(fs::FS &fs, const char *path, const char *message) tmp.close(); // Replace the target file atomically: remove existing then rename - if (fs.exists(finalPath.c_str())) - { - if (!fs.remove(finalPath.c_str())) - { + if (fs.exists(finalPath.c_str())) { + if (!fs.remove(finalPath.c_str())) { ESP_LOGE(tag, "Failed to remove existing file: %s", finalPath.c_str()); fs.remove(tmpPath.c_str()); return false; } } - if (!fs.rename(tmpPath.c_str(), finalPath.c_str())) - { + if (!fs.rename(tmpPath.c_str(), finalPath.c_str())) { ESP_LOGE(tag, "Failed to rename %s to %s", tmpPath.c_str(), finalPath.c_str()); fs.remove(tmpPath.c_str()); return false; @@ -1231,30 +1188,26 @@ bool writeFile(fs::FS &fs, const char *path, const char *message) return true; } -char *readFile(fs::FS &fs, const char *path) -{ +char *readFile(fs::FS &fs, const char *path) { static const char *tag = "readFile"; static const size_t MAX_FILE_SIZE = 1024 * 1024; // 1MB limit // Validate input - if (!path) - { + if (!path) { ESP_LOGE(tag, "Invalid path parameter"); return nullptr; } // Open file File file = fs.open(path, "r"); - if (!file || file.isDirectory()) - { + if (!file || file.isDirectory()) { ESP_LOGE(tag, "Failed to open file: %s", path); return nullptr; } // Check file size size_t fileSize = file.size(); - if (fileSize == 0 || fileSize > MAX_FILE_SIZE) - { + if (fileSize == 0 || fileSize > MAX_FILE_SIZE) { ESP_LOGE(tag, "Invalid file size: %u bytes", fileSize); file.close(); return nullptr; @@ -1262,8 +1215,7 @@ char *readFile(fs::FS &fs, const char *path) // Allocate memory char *fileContent = new (std::nothrow) char[fileSize + 1]; - if (!fileContent) - { + if (!fileContent) { ESP_LOGE(tag, "Memory allocation failed for size: %u", fileSize + 1); file.close(); return nullptr; @@ -1273,8 +1225,7 @@ char *readFile(fs::FS &fs, const char *path) size_t bytesRead = file.readBytes(fileContent, fileSize); file.close(); - if (bytesRead != fileSize) - { + if (bytesRead != fileSize) { ESP_LOGE(tag, "Read failed: expected %u bytes, got %u", fileSize, bytesRead); delete[] fileContent; return nullptr; @@ -1286,14 +1237,12 @@ char *readFile(fs::FS &fs, const char *path) return fileContent; } -String getSoftAPMacAddress() -{ +String getSoftAPMacAddress() { uint8_t mac[6]; WiFi.softAPmacAddress(mac); String macString = ""; - for (int i = 0; i < 6; i++) - { + for (int i = 0; i < 6; i++) { macString += String(mac[i], HEX); if (i < 5) macString += ":"; @@ -1301,47 +1250,107 @@ String getSoftAPMacAddress() return macString; } -String listDirAsHtml(String directoryList[], int count) -{ - String listedFiles; +String listDirAsHtml(String directoryList[], int count) { + // Validate input parameters + if (!directoryList || count <= 0 || count > MAX_DIRECTORIES) { + ESP_LOGW(tag, "Invalid parameters: directoryList=%p, count=%d", directoryList, count); + return String(); + } - for (int i = 0; i < count; i++) - { - // directory html - listedFiles += "Dir: "; - listedFiles += directoryList[i]; - listedFiles += "/-\n"; + // Pre-calculate estimated size to reduce reallocations + // Estimate: ~150 bytes per directory + ~120 bytes per file (conservative) + size_t estimatedSize = count * 300 + 512; // Extra buffer for safety + String result; + result.reserve(estimatedSize); - filesDropdownOptions += "\n"; + // Track statistics for debugging + int totalFiles = 0; + int totalDirs = 0; + int skippedDirs = 0; - dirDropdownOptions += "\n"; + for (int i = 0; i < count; i++) { + // Validate and normalize directory path + if (directoryList[i].isEmpty()) { + ESP_LOGD(tag, "Skipping empty directory path at index %d", i); + continue; + } - File dir = LittleFS.open(directoryList[i]); + String dirPath = directoryList[i]; + + // Security check: prevent directory traversal + if (dirPath.indexOf("..") >= 0) { + ESP_LOGW(tag, "Skipping directory with traversal attempt: %s", dirPath.c_str()); + skippedDirs++; + continue; + } + + // Normalize path efficiently + if (!dirPath.startsWith("/")) { + dirPath = "/" + dirPath; + } + + // Replace multiple slashes with single slash (more efficient than while loop) + dirPath.replace("//", "/"); + if (dirPath.indexOf("//") >= 0) { + // If still contains //, do more thorough cleanup + while (dirPath.indexOf("//") >= 0) { + dirPath.replace("//", "/"); + } + } + + // Generate directory row HTML with better formatting + result += "📁 "; + result += dirPath; + result += "/-\n"; + totalDirs++; + + // Open directory with error handling + File dir = LittleFS.open(dirPath); + if (!dir) { + ESP_LOGW(tag, "Cannot open directory: %s", dirPath.c_str()); + skippedDirs++; + continue; + } + + if (!dir.isDirectory()) { + ESP_LOGW(tag, "Path is not a directory: %s", dirPath.c_str()); + dir.close(); + skippedDirs++; + continue; + } + + // Process files in directory File file = dir.openNextFile(); - while (file) - { - String fileName = file.name(); - if (!file.isDirectory()) - { - // Serial.println(" File: " + String(file.name())); - listedFiles += "  "; - listedFiles += fileName; - listedFiles += ""; - listedFiles += convertFileSize(file.size()); - listedFiles += "\n"; + while (file) { + if (!file.isDirectory()) { + String fileName = file.name(); + String filePath = file.path(); + size_t fileSize = file.size(); + + // Validate file data + if (fileName.isEmpty()) { + ESP_LOGD(tag, "Skipping file with empty name in %s", dirPath.c_str()); + file = dir.openNextFile(); + continue; + } + // Build file row HTML efficiently + result += "  📄 "; + result += fileName; + result += ""; + result += convertFileSize(fileSize); + result += "\n"; + + totalFiles++; + + // Update global dropdown options (maintaining compatibility) filesDropdownOptions += "\n"; @@ -1349,196 +1358,173 @@ String listDirAsHtml(String directoryList[], int count) file = dir.openNextFile(); } dir.close(); + + // Update directory dropdown options (maintaining compatibility) + dirDropdownOptions += "\n"; } - return listedFiles; + // Log summary for debugging + ESP_LOGD(tag, "Listed %d directories (%d skipped), %d files. HTML size: %d bytes", + totalDirs, skippedDirs, totalFiles, result.length()); + + return result; } /******************** Specific Html Processors ********************/ // file manager html processor -String fileManagerHtmlProcessor(const String &var) -{ - if (var == "ALLOWED_EXTENSIONS_EDIT") - { +String fileManagerHtmlProcessor(const String &var) { + if (var == "ALLOWED_EXTENSIONS_EDIT") { return allowedExtensionsForEdit; } - if (var == "FS_FREE_BYTES") - { + if (var == "FS_FREE_BYTES") { return convertFileSize(LittleFS.totalBytes() - LittleFS.usedBytes()); } - if (var == "FS_USED_BYTES") - { + if (var == "FS_USED_BYTES") { return convertFileSize(LittleFS.usedBytes()); } - if (var == "FS_TOTAL_BYTES") - { + if (var == "FS_TOTAL_BYTES") { return convertFileSize(LittleFS.totalBytes()); } - if (var == "RAM_FREE_BYTES") - { + if (var == "RAM_FREE_BYTES") { return convertFileSize(LittleFS.totalBytes()); } - if (var == "RAM_USED_BYTES") - { + if (var == "RAM_USED_BYTES") { return convertFileSize(LittleFS.totalBytes()); } - if (var == "RAM_TOTAL_BYTES") - { + if (var == "RAM_TOTAL_BYTES") { return convertFileSize(LittleFS.totalBytes()); } - if (var == "LISTED_FILES") - { + if (var == "LISTED_FILES") { filesDropdownOptions = ""; // clear out dirDropdownOptions = ""; // clear out - String directories[MAX_DIRECTORIES]; + String *directories = new (std::nothrow) String[MAX_DIRECTORIES]; + if (!directories) { + ESP_LOGE(tag, "Failed to allocate directories array"); + return String(); + } int dirCount = 0; getAllDirectories(directories, dirCount); - return listDirAsHtml(directories, dirCount); + String out = listDirAsHtml(directories, dirCount); + delete[] directories; + return out; } - if (var == "EDIT-DEL_FILES") - { + if (var == "EDIT-DEL_FILES") { return filesDropdownOptions; } - if (var == "DIR_LIST") - { + if (var == "DIR_LIST") { return dirDropdownOptions; } - if (var == "SAVE_PATH_INPUT") - { + if (var == "SAVE_PATH_INPUT") { return savePath; } - if (var == "FIRM_VER") - { + if (var == "FIRM_VER") { return localVersion.toString(); } return var; } -String HomeHtmlProcessor(const String &var) -{ - if (var == "APP_NAME") - { +String HomeHtmlProcessor(const String &var) { + if (var == "APP_NAME") { // return sysProps.appName; return "N/A"; } - if (var == "OLED") - { + if (var == "OLED") { return "N/A"; } - if (var == "STRIP1") - { + if (var == "STRIP1") { // return (strip1) ? "Yes" : "No"; return "N/A"; } - if (var == "STRIP2") - { + if (var == "STRIP2") { // return (strip2) ? "Yes" : "No"; return "N/A"; } - if (var == "FRONT_LIGHT") - { + if (var == "FRONT_LIGHT") { // return (animProps.frontLight.enabled) ? "Yes" : "No"; return "N/A"; } - if (var == "REAR_LIGHT") - { + if (var == "REAR_LIGHT") { // return (animProps.rearLight.enabled) ? "Yes" : "No"; return "N/A"; } - if (var == "FIRMWARE") - { + if (var == "FIRMWARE") { return localVersion.toString(); } - if (var == "BOOTH_T") - { + if (var == "BOOTH_T") { // return String(sysProps.t_sensor.temperature) + "F"; return "N/A"; } - if (var == "SETPOINT") - { + if (var == "SETPOINT") { // return String(sysProps.t_sensor.Setpoint1) + "F"; return "N/A"; } - if (var == "FLASH_SIZE") - { + if (var == "FLASH_SIZE") { return convertFileSize(ESP.getSketchSize()); } - if (var == "FLASH_FREE") - { + if (var == "FLASH_FREE") { return convertFileSize(ESP.getFreeSketchSpace()); } - if (var == "HEAP_SIZE") - { + if (var == "HEAP_SIZE") { return convertFileSize(ESP.getHeapSize()); } - if (var == "HEAP_FREE") - { + if (var == "HEAP_FREE") { return convertFileSize(ESP.getFreeHeap()); } - if (var == "CPU_FREQ") - { + if (var == "CPU_FREQ") { return String(ESP.getCpuFreqMHz()) + "Mhz"; } - if (var == "IP") - { + if (var == "IP") { return WiFi.localIP().toString(); } - if (var == "MAC") - { + if (var == "MAC") { return chipInfo.macStr; } - if (var == "SSID") - { + if (var == "SSID") { return WiFi.SSID(); } - if (var == "RSSI") - { + if (var == "RSSI") { return String(WiFi.RSSI()); } - if (var == "WIFI_CH") - { + if (var == "WIFI_CH") { return String(WiFi.channel()); } - if (var == "ENCRYP") - { + if (var == "ENCRYP") { return String(WiFi.encryptionType(0)); } - if (var == "AP_SSID") - { + if (var == "AP_SSID") { return WiFi.softAPSSID(); } - if (var == "AP_CLIENTS") - { + if (var == "AP_CLIENTS") { return String(WiFi.softAPgetStationNum()); } - if (var == "BLE") - { + if (var == "BLE") { return (commMode == COMM_WIFI_AP_BLE) ? "Yes" : "No"; } - if (var == "BLE_SSID") - { + if (var == "BLE_SSID") { // return (commMode == COMM_WIFI_AP_BLE) ? BLEDeviceName : ""; return "N/A"; } - if (var == "BLE_CLIENTS") - { + if (var == "BLE_CLIENTS") { // return (BTDeviceConnected) ? "1" : "0"; return "N/A"; } - if (var == "AP_MAC") - { + if (var == "AP_MAC") { return getSoftAPMacAddress(); } @@ -1546,8 +1532,7 @@ String HomeHtmlProcessor(const String &var) return var; } -void handleUpdateProgress(AsyncWebServerRequest *request) -{ +void handleUpdateProgress(AsyncWebServerRequest *request) { static const char *tag = "UpdateProgress"; // if (!request->authenticate(http_username, http_password)) { diff --git a/temporary/AppUpgrade copy.cpp b/temporary/AppUpgrade copy.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/temporary/AppUpgrade orig.cpp b/temporary/AppUpgrade orig.cpp deleted file mode 100644 index 91e6c90..0000000 --- a/temporary/AppUpgrade orig.cpp +++ /dev/null @@ -1,673 +0,0 @@ -#include "AppUpgrade.h" -#include "esp_log.h" -#include -#include -#include -#include "global.h" -#include "JsonConstrain.h" -#include "BLE_UpdateService.h" -#include -#include - -static const char* TAG = "AppUpdater"; -TaskHandle_t Update_Task_Handle = NULL; -TaskHandle_t versionCheckTask_Handle = NULL; - -// Queue handle for firmware update messages -//QueueHandle_t updateMsgQueue = NULL; - -String updateUrl = ""; - -Version otaVersion; - - -AppUpdater::AppUpdater(fs::FS& fs, Version localVersion, const char* bucket, const char* manifestName, const char* appBin) - : localVersion(localVersion), manifestName(manifestName), appName(appBin), fileSystem(fs), downloadBuffer(new uint8_t[BUFFER_SIZE]) -{ - baseUrl = bucket ? String(bucket) : String(DEFAULT_MANIFEST_URL); - // Ensure baseUrl ends with a single '/' - if(!baseUrl.endsWith("/")) baseUrl += "/"; - ESP_LOGI(TAG, "AppUpdater initialized (local v%s) baseUrl=%s", localVersion.toString().c_str(), baseUrl.c_str()); -} - -void AppUpdater::setProgressCallback(void (*callback)( UpdateStatus status, int percentage, const char* message)) { - progressCb = callback; -} - -void AppUpdater::updateProgress(UpdateStatus newStatus, int percentage, const char* message) { - status = newStatus; - if (progressCb) { - progressCb(status, percentage, message); - } -} - -bool AppUpdater::checkManifest() { - String url = buildUrl(manifestName); - ESP_LOGD(TAG, "Fetching manifest from: %s", url.c_str()); - - // Start the HTTP client and Send GET request for manifest - HTTPClient http; - http.begin(url); - int httpCode = http.GET(); - if (httpCode != HTTP_CODE_OK) { - ESP_LOGE(TAG, "HTTP GET failed, error: %d", httpCode); - http.end(); - return false; - } - - // Read the response - String payload = http.getString(); - http.end(); - - // Parse JSON - DeserializationError error = deserializeJson(jsonManifest, payload); - ESP_LOGD(TAG, "Manifest deserialized"); - if (error) { - ESP_LOGE(TAG, "Failed to parse manifest: %s", error.c_str()); - return false; - } - - // Check for files section - jsonFilesArray = jsonManifest["files"]; - if (jsonFilesArray.isNull()) { - ESP_LOGE(TAG, "No files section in manifest"); - return false; - }else{ - ESP_LOGD(TAG, "%d Files found", jsonFilesArray.size()); - } - - // Check for version section - JsonObject jsonVersion = jsonManifest["version"]; - ESP_LOGD(TAG, "Version section found"); - if (jsonVersion.isNull()) { - ESP_LOGE(TAG, "No version section in manifest"); - return false; - } - - // Get the remote version - byte major = jsonVersion["major"] | 0; - byte minor = jsonVersion["minor"] | 0; - byte patch = jsonVersion["patch"] | 0; - otaVersion = {major, minor, patch}; - - //Version localVersion; - //::sscanf(localVersion, "%d.%d.%d", &localVersion.major, &localVersion.minor, &localVersion.patch); - - // Check if an update is available - updateAvailable = false; - // Only mark update available if remote is strictly newer than local - if (otaVersion <= localVersion) { - ESP_LOGI(TAG, "No updates available"); - return false; - }else{ - updateAvailable = true; - ESP_LOGD(TAG, "Update available"); - } - - //ESP_LOGD(TAG, "Manifest content: %s", payload.c_str()); - - return true; -} - -bool AppUpdater::updateFile(const char* remotePath, const char* localPath, const char* expectedMd5) { - //updateProgress(UpdateStatus::DOWNLOADING, 0, localPath); - - // Construct full URL - String url = buildUrl(remotePath); - ESP_LOGD(TAG, "Downloading: %s -> %s", url.c_str(), localPath); - - String localMd5 = getLocalMD5(localPath); - - if (localMd5.equals(expectedMd5)) { - ESP_LOGI(TAG, "File already up to date: %s", localPath); - updateProgress(UpdateStatus::FILE_SKIPPED, 100, localPath); - return true; - } - - // Start the download - HTTPClient http; - http.begin(url); - int httpCode = http.GET(); - if (httpCode != HTTP_CODE_OK) { - ESP_LOGE(TAG, "Download failed: %d", httpCode); - updateProgress(UpdateStatus::ERROR, 0, "Download failed"); - http.end(); - return false; - } - - // Get the stream and content length - WiFiClient* stream = http.getStreamPtr(); - size_t contentLength = http.getSize(); - - // Verify and save the file - bool success = verifyAndSaveFile(stream, contentLength, localPath, expectedMd5); - http.end(); - if(!success){ - updateProgress( UpdateStatus::ERROR, 0, "MD5 verification failed"); - }else{ - updateProgress( UpdateStatus::FILE_SAVED, 100, localPath); - } - - return success; -} - -bool AppUpdater::verifyAndSaveFile(WiFiClient* stream, size_t contentLength, const char* localPath, const char* expectedMd5) -{ - MD5Builder md5; - md5.begin(); - size_t totalRead = 0; - - // Create temporary filename - String tempPath = String(localPath) + ".tmp"; - - // Open temporary file for writing - File file = fileSystem.open(tempPath.c_str(), FILE_WRITE); - if (!file) { - ESP_LOGE(TAG, "Failed to open temporary file for writing"); - return false; - } - - //updateProgress(UpdateStatus::DOWNLOADING, 0, localPath); - - if (contentLength > 0) { - // Single pass with known content length - while (totalRead < contentLength) { - size_t available = stream->available(); - if (available) { - size_t readLen = stream->readBytes(downloadBuffer.get(), std::min(available, size_t(BUFFER_SIZE))); - - // Write to temp file and update MD5 - if (file.write(downloadBuffer.get(), readLen) != readLen) { - ESP_LOGE(TAG, "Failed to write to temporary file"); - - file.close(); - fileSystem.remove(tempPath.c_str()); - return false; - } - - md5.add(downloadBuffer.get(), readLen); - totalRead += readLen; - updateProgress(UpdateStatus::DOWNLOADING, (totalRead * 90) / contentLength , localPath); - } - yield(); - } - } else { - // Unknown content length: read until stream ends - for (;;) { - size_t readLen = stream->readBytes(downloadBuffer.get(), BUFFER_SIZE); - if (readLen == 0) { - break; - } - if (file.write(downloadBuffer.get(), readLen) != readLen) { - ESP_LOGE(TAG, "Failed to write to temporary file"); - file.close(); - fileSystem.remove(tempPath.c_str()); - return false; - } - md5.add(downloadBuffer.get(), readLen); - totalRead += readLen; - // Progress unknown; emit periodic heartbeats at 0% - updateProgress(UpdateStatus::DOWNLOADING, 0, localPath); - yield(); - } - } - - file.close(); - md5.calculate(); - String calculatedMd5 = md5.toString(); - - // Verify MD5 hash - if (!calculatedMd5.equals(expectedMd5)) { - //ESP_LOGE(TAG, "MD5 mismatch for %s", localPath); - fileSystem.remove(tempPath.c_str()); - return false; - } - - // Replace original file with verified temp file - if (fileSystem.exists(localPath)) { - fileSystem.remove(localPath); - } - if (!fileSystem.rename(tempPath.c_str(), localPath)) { - ESP_LOGE(TAG, "Failed to rename temporary file"); - fileSystem.remove(tempPath.c_str()); - return false; - } - - return true; -} - -String AppUpdater::getLocalMD5(const char* filePath){ - File file = fileSystem.open(filePath, "r"); - if(!file){ - ESP_LOGE(TAG, "Error opening %s...", filePath); - return String(); - } - - MD5Builder md5Builder; - md5Builder.begin(); - size_t fileSize = file.size(); - size_t totalRead = 0; - size_t readLen = 0; - while (totalRead < fileSize) { - readLen = file.readBytes(reinterpret_cast(downloadBuffer.get()), std::min(fileSize - totalRead, size_t(BUFFER_SIZE))); - md5Builder.add(downloadBuffer.get(), readLen); - totalRead += readLen; - } - - md5Builder.calculate(); - file.close(); - return md5Builder.toString(); -} - -bool AppUpdater::updateFilesArray() { - int successCount = 0; - int totalFiles = jsonFilesArray.size(); - ESP_LOGI(TAG, "Found %d files in manifest", totalFiles); - - // Iterate over each file entry in the manifest - for (JsonObject file : jsonFilesArray) { - const char* remotePath = file["remote"]; - const char* localPath = file["local"]; - const char* expectedMd5 = file["md5"]; - - // Skip invalid entries - if (!remotePath || !localPath || !expectedMd5) { - ESP_LOGE(TAG, "Invalid file entry in manifest"); - continue; - } - - // Attempt to update the file - if (updateFile(remotePath, localPath, expectedMd5)) { - successCount++; - } - } - - ESP_LOGI(TAG, "Manifest update complete: %d/%d files updated", successCount, totalFiles); - return successCount == totalFiles; -} - -bool AppUpdater::updateApp() { - updateProgress(UpdateStatus::MESSAGE, 0, "Starting firmware update"); - - // Check for firmware section in manifest - if (!jsonManifest["firmware"].is() || !jsonManifest["firmware"]["md5"].is()) { - ESP_LOGE(TAG, "Invalid firmware section in manifest"); - updateProgress(UpdateStatus::ERROR, 0, "Firmware: Invalid firmware section in manifest"); - return false; - } - - // Get the firmware MD5 hash and URL - const char* expectedMd5 = jsonManifest["firmware"]["md5"]; - String firmwareUrl = buildUrl(appName); - - // Download the firmware - HTTPClient http; - http.begin(firmwareUrl); - int httpCode = http.GET(); - if (httpCode != HTTP_CODE_OK) { - ESP_LOGE(TAG, "Firmware download failed: %d", httpCode); - updateProgress(UpdateStatus::ERROR, 0, "Firmware: Firmware download failed"); - http.end(); - return false; - } - - // Check available space - size_t firmwareSize = http.getSize(); - if (!Update.begin(firmwareSize > 0 ? firmwareSize : UPDATE_SIZE_UNKNOWN)) { - ESP_LOGE(TAG, "Firmware: Not enough space for update"); - updateProgress(UpdateStatus::ERROR, 0, "Firmware: Not enough space for update"); - http.end(); - return false; - } - - // Set up MD5 checking - MD5Builder md5; - md5.begin(); - - // Download and verify firmware - WiFiClient* stream = http.getStreamPtr(); - if (firmwareSize > 0) { - size_t remaining = firmwareSize; - while (remaining > 0) { - size_t chunk = std::min(remaining, size_t(BUFFER_SIZE)); - size_t read = stream->readBytes(downloadBuffer.get(), chunk); - - // Check for timeout - if (read == 0) { - ESP_LOGE(TAG, "Read timeout"); - Update.abort(); - http.end(); - return false; - } - - // Update MD5 and write firmware - md5.add(downloadBuffer.get(), read); - if (Update.write(downloadBuffer.get(), read) != read) { - ESP_LOGE(TAG, "Write failed"); - Update.abort(); - http.end(); - return false; - } - - remaining -= read; - updateProgress(UpdateStatus::DOWNLOADING, (firmwareSize - remaining) * 100 / firmwareSize, "firmware"); - } - } else { - // Unknown size: stream until end - for (;;) { - size_t read = stream->readBytes(downloadBuffer.get(), BUFFER_SIZE); - if (read == 0) break; - md5.add(downloadBuffer.get(), read); - if (Update.write(downloadBuffer.get(), read) != read) { - ESP_LOGE(TAG, "Write failed"); - Update.abort(); - http.end(); - return false; - } - updateProgress(UpdateStatus::DOWNLOADING, 0, "firmware"); - } - } - - // Verify MD5 - md5.calculate(); - String calculatedMd5 = md5.toString(); - if (!calculatedMd5.equals(expectedMd5)) { - ESP_LOGE(TAG, "MD5 mismatch. Expected: %s, Got: %s", expectedMd5, calculatedMd5.c_str()); - updateProgress(UpdateStatus::MD5_FAILED, 0, "Firmware: MD5 mismatch"); - Update.abort(); - http.end(); - return false; - } - - // Finish update - if (!Update.end()) { - ESP_LOGE(TAG, "Update end failed"); - updateProgress(UpdateStatus::ERROR, 0, "Firmware: Update failed"); - http.end(); - return false; - } - - http.end(); - updateProgress(UpdateStatus::COMPLETE, 0, "Firmware: Complete"); - return true; -} - -bool AppUpdater::IsUpdateAvailable(){ - return updateAvailable; -} - -String AppUpdater::buildUrl(const char* path) const { - if(!path || !*path) return baseUrl; // just base - String p(path); - // If already absolute URL, pass through - if(p.startsWith("http://") || p.startsWith("https://")) return p; - // Strip leading slashes to avoid double - while(p.startsWith("/")) p.remove(0,1); - // Ensure baseUrl has single trailing slash - String b = baseUrl; - if(!b.endsWith("/")) b += "/"; - return b + p; -} - - -AsyncEventSource* eventProgress = nullptr; -void startFirmwareUpdateTask(AsyncEventSource* evProg) { - eventProgress = evProg; - if(Update_Task_Handle) { - ESP_LOGW(TAG, "Firmware update task already running"); - return; - } - xTaskCreate(firmwareUpdateTask, "FirmwareUpdate", 1024*8, NULL, 1, &Update_Task_Handle); -} - -void firmwareUpdateTask(void* parameter) { - static const char* TAG = "UpdateTask"; - AppUpdater* updater = nullptr; - - try { - loadUpdateJson(); - - // Initialize updater - updater = new AppUpdater(LittleFS, localVersion, updateUrl.c_str(), "update.json", "firmware.bin"); - updater->setProgressCallback(updateProgress); - - ESP_LOGI(TAG, "Starting update check from: %s", updateUrl.c_str()); - - // Check and perform updates - if (!updater->checkManifest()) { throw std::runtime_error("Failed to check manifest"); } - - if (updater->IsUpdateAvailable()) { - ESP_LOGI(TAG, "Update available, updating files..."); - - if (!updater->updateFilesArray()) { - throw std::runtime_error("Failed to update files"); - } - - ESP_LOGI(TAG, "Updating firmware..."); - if (!updater->updateApp()) { - throw std::runtime_error("Failed to update firmware"); - } - ESP_LOGI(TAG, "Update successful, restarting..."); - - sendUpdateMessage("Restarting ", true, 100); - vTaskDelay(2000); - - ESP.restart(); - - } - - } catch (const std::exception& e) { - ESP_LOGE(TAG, "Update failed: %s", e.what()); - } - end: - delete updater; - Update_Task_Handle = NULL; - vTaskDelete(NULL); -} - -void startVersionCheckTask() { - if(versionCheckTask_Handle != NULL) { - ESP_LOGW(TAG, "Version Check Tak already running"); - return; - } - xTaskCreate(versionCheckTask, "VersionCheckTask", 1024*8, NULL, 1, &versionCheckTask_Handle); -} - -void versionCheckTask(void* parameter){ - - if(updateUrl == ""){ - loadUpdateJson(); - } - - if(checkManifest(otaVersion) == false){ - ESP_LOGE(TAG, "Error checking manifest"); - } - - versionCheckTask_Handle = NULL; - vTaskDelete(NULL); -} - -void loadUpdateJson(void) { - try { - ESP_LOGD(TAG, "loadUpdateJaon function..."); - if(updateUrl == "") { - String updateJsonPath = "/system/update.json"; - - // Read and parse update.json - File file = LittleFS.open(updateJsonPath); - if (!file) { - throw std::runtime_error("Failed to open update.json"); - } - - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - - if (error) { throw std::runtime_error("Failed to parse update.json"); } - - // Get update configuration - JsonObject jObj = doc.as(); - String folderName = jsonConstrainString(TAG, jObj, "folder", "latest/"); - String baseUrl = jsonConstrainString(TAG, jObj, "baseurl", "https://s3-minio.boothwizard.com/boothifier/"); - updateUrl = baseUrl + folderName; - - ESP_LOGD(TAG, "updateUrl: %s", updateUrl.c_str()); - } - } catch (const std::exception& e) { - ESP_LOGE(TAG, "Update failed: %s", e.what()); - } -} - -void updateProgress(AppUpdater::UpdateStatus newStatus, int percentage, const char* message = nullptr) { - - char buffer[128]; - const char* msg; - bool isComplete = false; - - const char* safeMsg = message ? message : ""; - switch (newStatus) { - case AppUpdater::UpdateStatus::IDLE: - snprintf(buffer, sizeof(buffer), "Update idle"); - msg = buffer; - break; - case AppUpdater::UpdateStatus::MESSAGE: - msg = message ? message : ""; - break; - case AppUpdater::UpdateStatus::DOWNLOADING: - snprintf(buffer, sizeof(buffer), "%s: Download progress: %d%%", safeMsg, percentage); - msg = buffer; - break; - case AppUpdater::UpdateStatus::VERIFYING: - snprintf(buffer, sizeof(buffer), "%s: Verifying update: %d%%", safeMsg, percentage); - msg = buffer; - break; - case AppUpdater::UpdateStatus::FILE_SKIPPED: - snprintf(buffer, sizeof(buffer), "%s: Skipping file update, already up to date", safeMsg); - msg = buffer; - break; - case AppUpdater::UpdateStatus::FILE_SAVED: - snprintf(buffer, sizeof(buffer), "%s: File Saved", safeMsg); - msg = buffer; - break; - case AppUpdater::UpdateStatus::MD5_FAILED: - snprintf(buffer, sizeof(buffer), "%s: MD5 Verification Failed", safeMsg); - msg = buffer; - break; - case AppUpdater::UpdateStatus::COMPLETE: - snprintf(buffer, sizeof(buffer), "Firmware Update Complete!!!"); - msg = buffer; - isComplete = true; - break; - case AppUpdater::UpdateStatus::ERROR: - snprintf(buffer, sizeof(buffer), "Error!: %s", safeMsg); - msg = buffer; - break; - default: - snprintf(buffer, sizeof(buffer), "Unknown update status: %d", (int)newStatus); - msg = buffer; - break; - } - - ESP_LOGI(TAG, "%s", msg); - sendUpdateMessage(msg, isComplete, percentage); -} - -void sendUpdateMessage(const char* message, bool complete, int progress = -1) { - if(eventProgress && eventProgress->count() > 0) { - JsonDocument jsonDoc; - jsonDoc["message"] = message; - jsonDoc["complete"] = complete; - jsonDoc["progress"] = progress; - String strMessage; - serializeJson(jsonDoc, strMessage); - eventProgress->send(strMessage.c_str(), "update", millis()); - } - else{ - ESP_LOGW(TAG, "No clients connected to event source"); - } - - bleUpgrade_send_message(message); -} - -bool checkManifest(Version& remoteVersion) { - const char* TAG = "manifestCheck"; - String url = updateUrl + "update.json"; - ESP_LOGD(TAG, "Fetching manifest from: %s", url.c_str()); - - // Start the HTTP client and send GET request for manifest - HTTPClient http; - http.begin(url); - int httpCode = http.GET(); - if (httpCode != HTTP_CODE_OK) { - ESP_LOGE(TAG, "HTTP GET failed, error: %d", httpCode); - http.end(); - return false; - } - - // Read the response - String payload = http.getString(); - http.end(); - - //ESP_LOGD(TAG, "%s", payload.c_str()); - - // Parse JSON - JsonDocument jsonManifest; - DeserializationError error = deserializeJson(jsonManifest, payload); - if (error) { - ESP_LOGE(TAG, "Failed to parse manifest: %s", error.c_str()); - return false; - } - - // Check for version section - JsonObject jsonVersion = jsonManifest["version"]; - - if (jsonVersion.isNull()) { - ESP_LOGE(TAG, "No version section in manifest"); - return false; - } - - // Get the remote version - byte major = jsonVersion["major"] | 0; - byte minor = jsonVersion["minor"] | 0; - byte patch = jsonVersion["patch"] | 0; - remoteVersion = {major, minor, patch}; - ESP_LOGI(TAG, "Remote version: %s", remoteVersion.toString().c_str()); - return true; -} - -/* -void setup() { - Serial.begin(115200); - - // Initialize WiFi connection first - // ... WiFi connection code ... - - // Initialize filesystem - if(!LittleFS.begin()) { - Serial.println("LittleFS Mount Failed"); - return; - } - - // Create updater instance with: - // - Current version: "1.0.0" - // - Update server URL: "https://my-update-server.com/" - // - Filesystem: LittleFS - AppUpdater updater("1.0.0", "https://storage.googleapis.com/boothifier/latest/", LittleFS); - - // Set progress callback - updater.setProgressCallback([](int progress) { - Serial.printf("Update progress: %d%%\n", progress); - }); - - // Check and update firmware - if (updater.checkAndUpdate()) { - Serial.println("Update successful! Rebooting..."); - ESP.restart(); - } - - // Update specific files from manifest - int updatedFiles = updater.updateFilesFromManifest("test_update.json"); - Serial.printf("Updated %d files\n", updatedFiles); -} - -*/ \ No newline at end of file diff --git a/temporary/AppUpgrade_orig.cpp b/temporary/AppUpgrade_orig.cpp deleted file mode 100644 index 2d72a74..0000000 --- a/temporary/AppUpgrade_orig.cpp +++ /dev/null @@ -1,716 +0,0 @@ -#include "AppUpgrade.h" -#include "esp_log.h" -#include -#include -#include -#include "global.h" -#include "JsonConstrain.h" -#include "BLE_UpdateService.h" -#include -#include -#include - -static const char* TAG = "AppUpdater"; -TaskHandle_t Update_Task_Handle = NULL; -TaskHandle_t versionCheckTask_Handle = NULL; -volatile bool g_UpdateCancelFlag = false; // cancellation flag -String updateUrl = ""; -Version otaVersion; - - -AppUpdater::AppUpdater(fs::FS& fs, Version localVersion, const char* bucket, const char* manifestName, const char* appBin) - : localVersion(localVersion), manifestName(manifestName), appName(appBin), fileSystem(fs), downloadBuffer(new uint8_t[BUFFER_SIZE]) -{ - baseUrl = bucket ? String(bucket) : String(DEFAULT_MANIFEST_URL); - // Ensure baseUrl ends with a single '/' - if(!baseUrl.endsWith("/")) baseUrl += "/"; - ESP_LOGI(TAG, "AppUpdater initialized (local v%s) baseUrl=%s", localVersion.toString().c_str(), baseUrl.c_str()); -} - -void AppUpdater::setProgressCallback(void (*callback)( UpdateStatus status, int percentage, const char* message)) { - progressCb = callback; -} - -void AppUpdater::updateProgress(UpdateStatus newStatus, int percentage, const char* message) { - status = newStatus; - if (progressCb) { - progressCb(status, percentage, message); - } -} - -AppUpdater::ManifestCheckResult AppUpdater::checkManifest() { - String url = buildUrl(manifestName); - ESP_LOGD(TAG, "Fetching manifest from: %s", url.c_str()); - - String payload; - for(int attempt=0; attempt MAX_MANIFEST_SIZE){ - ESP_LOGE(TAG, "Manifest too large (%u bytes)", (unsigned)payload.length()); - return ManifestCheckResult::ERROR_TOO_LARGE; - } - - // Parse JSON - DeserializationError error = deserializeJson(jsonManifest, payload); - ESP_LOGD(TAG, "Manifest deserialized"); - if (error) { - ESP_LOGE(TAG, "Failed to parse manifest: %s", error.c_str()); - return ManifestCheckResult::ERROR_PARSE_FAILED; - } - - // Check for files section - jsonFilesArray = jsonManifest["files"]; - if (jsonFilesArray.isNull()) { - ESP_LOGE(TAG, "No files section in manifest"); - return ManifestCheckResult::ERROR_NO_FILES_SECTION; - }else{ - ESP_LOGD(TAG, "%d Files found", jsonFilesArray.size()); - } - - // Check for version section - JsonObject jsonVersion = jsonManifest["version"]; - ESP_LOGD(TAG, "Version section found"); - if (jsonVersion.isNull()) { - ESP_LOGE(TAG, "No version section in manifest"); - return ManifestCheckResult::ERROR_NO_VERSION; - } - - // Get the remote version - byte major = jsonVersion["major"] | 0; - byte minor = jsonVersion["minor"] | 0; - byte patch = jsonVersion["patch"] | 0; - otaVersion = {major, minor, patch}; - - //Version localVersion; - //::sscanf(localVersion, "%d.%d.%d", &localVersion.major, &localVersion.minor, &localVersion.patch); - - // Check if an update is available - updateAvailable = false; - // Only mark update available if remote is strictly newer than local - if (otaVersion <= localVersion) { - ESP_LOGI(TAG, "No updates available: remote=%s, local=%s", - otaVersion.toString().c_str(), localVersion.toString().c_str()); - return ManifestCheckResult::VERSION_CURRENT; - }else{ - updateAvailable = true; - ESP_LOGI(TAG, "Update available: remote=%s, local=%s", - otaVersion.toString().c_str(), localVersion.toString().c_str()); - } - - //ESP_LOGD(TAG, "Manifest content: %s", payload.c_str()); - - return ManifestCheckResult::UPDATE_AVAILABLE; -} - -bool AppUpdater::updateFile(const char* remotePath, const char* localPath, const char* expectedMd5) { - //updateProgress(UpdateStatus::DOWNLOADING, 0, localPath); - - // Construct full URL - String url = buildUrl(remotePath); - ESP_LOGD(TAG, "Downloading: %s -> %s", url.c_str(), localPath); - - // Quick skip: if exists and size & MD5 match - bool skip = false; - if(fileSystem.exists(localPath)){ - String localMd5 = getLocalMD5(localPath); - if(localMd5.equals(expectedMd5)) skip = true; - } - if(skip){ - ESP_LOGI(TAG, "File already up to date: %s", localPath); - updateProgress(UpdateStatus::FILE_SKIPPED, 100, localPath); - return true; - } - - // Start the download - HTTPClient http; - int httpCode = -1; - for(int attempt=0; attempt 0) { - // Single pass with known content length - while (totalRead < contentLength) { - if(g_UpdateCancelFlag){ file.close(); fileSystem.remove(tempPath.c_str()); return false; } - size_t available = stream->available(); - if (available) { - size_t readLen = stream->readBytes(downloadBuffer.get(), std::min(available, size_t(BUFFER_SIZE))); - - // Write to temp file and update MD5 - if (file.write(downloadBuffer.get(), readLen) != readLen) { - ESP_LOGE(TAG, "Failed to write to temporary file"); - - file.close(); - fileSystem.remove(tempPath.c_str()); - return false; - } - - md5.add(downloadBuffer.get(), readLen); - totalRead += readLen; - updateProgress(UpdateStatus::DOWNLOADING, (totalRead * 80) / contentLength , localPath); - } - yield(); - } - } else { - // Unknown content length: read until stream ends - for (;;) { - if(g_UpdateCancelFlag){ file.close(); fileSystem.remove(tempPath.c_str()); return false; } - size_t readLen = stream->readBytes(downloadBuffer.get(), BUFFER_SIZE); - if (readLen == 0) { - break; - } - if (file.write(downloadBuffer.get(), readLen) != readLen) { - ESP_LOGE(TAG, "Failed to write to temporary file"); - file.close(); - fileSystem.remove(tempPath.c_str()); - return false; - } - md5.add(downloadBuffer.get(), readLen); - totalRead += readLen; - // Progress unknown; emit periodic heartbeats at 0% - // For unknown size, send heartbeats every ~16KB - if((totalRead & 0x3FFF) == 0){ - updateProgress(UpdateStatus::DOWNLOADING, 0, localPath); - } - yield(); - } - } - - file.close(); - md5.calculate(); - String calculatedMd5 = md5.toString(); - - // Verify MD5 hash - updateProgress(UpdateStatus::VERIFYING, 90, localPath); - if (!calculatedMd5.equals(expectedMd5)) { - //ESP_LOGE(TAG, "MD5 mismatch for %s", localPath); - fileSystem.remove(tempPath.c_str()); - return false; - } - - updateProgress(UpdateStatus::VERIFYING, 95, localPath); - - // Replace original file with verified temp file - if (fileSystem.exists(localPath)) { - fileSystem.remove(localPath); - } - if (!fileSystem.rename(tempPath.c_str(), localPath)) { - ESP_LOGE(TAG, "Failed to rename temporary file"); - fileSystem.remove(tempPath.c_str()); - return false; - } - - updateProgress(UpdateStatus::VERIFYING, 100, localPath); - return true; -} - -String AppUpdater::getLocalMD5(const char* filePath){ - File file = fileSystem.open(filePath, "r"); - if(!file){ - ESP_LOGE(TAG, "Error opening %s...", filePath); - return String(); - } - - MD5Builder md5Builder; - md5Builder.begin(); - size_t fileSize = file.size(); - size_t totalRead = 0; - size_t readLen = 0; - while (totalRead < fileSize) { - readLen = file.readBytes(reinterpret_cast(downloadBuffer.get()), std::min(fileSize - totalRead, size_t(BUFFER_SIZE))); - md5Builder.add(downloadBuffer.get(), readLen); - totalRead += readLen; - } - - md5Builder.calculate(); - file.close(); - return md5Builder.toString(); -} - -bool AppUpdater::updateFilesArray() { - int successCount = 0; - int totalFiles = jsonFilesArray.size(); - ESP_LOGI(TAG, "Found %d files in manifest", totalFiles); - - // Iterate over each file entry in the manifest - for (JsonObject file : jsonFilesArray) { - const char* remotePath = file["path"]; - const char* localPath = remotePath; - // If path begins with "data/" or "/data/" strip only the "data" portion, retaining the leading slash - if (localPath) { - if (strncmp(localPath, "data/", 5) == 0) { - localPath += 4; // points to '/' - } else if (strncmp(localPath, "/data/", 6) == 0) { - localPath += 5; // points to '/' - } - } - const char* expectedMd5 = file["md5"]; - - // Skip invalid entries - if (!remotePath || !localPath || !expectedMd5) { - ESP_LOGE(TAG, "Invalid file entry in manifest"); - continue; - } - - // Attempt to update the file - if (updateFile(remotePath, localPath, expectedMd5)) { - successCount++; - } - } - - ESP_LOGI(TAG, "Manifest update complete: %d/%d files updated", successCount, totalFiles); - return successCount == totalFiles; -} - -bool AppUpdater::updateApp() { - updateProgress(UpdateStatus::MESSAGE, 0, "Starting firmware update"); - - // Check for firmware section in manifest - if (!jsonManifest["firmware"].is() || !jsonManifest["firmware"]["md5"].is()) { - ESP_LOGE(TAG, "Invalid firmware section in manifest"); - updateProgress(UpdateStatus::ERROR, 0, "Firmware: Invalid firmware section in manifest"); - return false; - } - - // Get the firmware MD5 hash and URL - const char* expectedMd5 = jsonManifest["firmware"]["md5"]; - String firmwareUrl = buildUrl(appName); - - // Download the firmware - HTTPClient http; - int httpCode = -1; - for(int attempt=0; attempt 0 ? firmwareSize : UPDATE_SIZE_UNKNOWN)) { - ESP_LOGE(TAG, "Firmware: Not enough space for update"); - updateProgress(UpdateStatus::ERROR, 0, "Firmware: Not enough space for update"); - http.end(); - return false; - } - - // Set up MD5 checking - MD5Builder md5; - md5.begin(); - - // Download and verify firmware - WiFiClient* stream = http.getStreamPtr(); - if (firmwareSize > 0) { - size_t remaining = firmwareSize; - while (remaining > 0) { - if(g_UpdateCancelFlag){ Update.abort(); http.end(); return false; } - size_t chunk = std::min(remaining, size_t(BUFFER_SIZE)); - size_t read = stream->readBytes(downloadBuffer.get(), chunk); - - // Check for timeout - if (read == 0) { - ESP_LOGE(TAG, "Read timeout"); - Update.abort(); - http.end(); - return false; - } - - // Update MD5 and write firmware - md5.add(downloadBuffer.get(), read); - if (Update.write(downloadBuffer.get(), read) != read) { - ESP_LOGE(TAG, "Write failed"); - Update.abort(); - http.end(); - return false; - } - - remaining -= read; - updateProgress(UpdateStatus::DOWNLOADING, (firmwareSize - remaining) * 100 / firmwareSize, "firmware"); - } - } else { - // Unknown size: stream until end - for (;;) { - if(g_UpdateCancelFlag){ Update.abort(); http.end(); return false; } - size_t read = stream->readBytes(downloadBuffer.get(), BUFFER_SIZE); - if (read == 0) break; - md5.add(downloadBuffer.get(), read); - if (Update.write(downloadBuffer.get(), read) != read) { - ESP_LOGE(TAG, "Write failed"); - Update.abort(); - http.end(); - return false; - } - updateProgress(UpdateStatus::DOWNLOADING, 0, "firmware"); - } - } - - // Verify MD5 - md5.calculate(); - String calculatedMd5 = md5.toString(); - updateProgress(UpdateStatus::VERIFYING, 95, "firmware"); - if (!calculatedMd5.equals(expectedMd5)) { - ESP_LOGE(TAG, "MD5 mismatch. Expected: %s, Got: %s", expectedMd5, calculatedMd5.c_str()); - updateProgress(UpdateStatus::MD5_FAILED, 0, "Firmware: MD5 mismatch"); - Update.abort(); - http.end(); - return false; - } - - // Finish update - if (!Update.end()) { - ESP_LOGE(TAG, "Update end failed"); - updateProgress(UpdateStatus::ERROR, 0, "Firmware: Update failed"); - http.end(); - return false; - } - - http.end(); - updateProgress(UpdateStatus::COMPLETE, 100, "Firmware: Complete"); - return true; -} - -bool AppUpdater::IsUpdateAvailable(){ - return updateAvailable; -} - -String AppUpdater::buildUrl(const char* path) const { - if(!path || !*path) return baseUrl; // just base - String p(path); - // If already absolute URL, pass through - if(p.startsWith("http://") || p.startsWith("https://")) return p; - // Strip leading slashes to avoid double - while(p.startsWith("/")) p.remove(0,1); - // Ensure baseUrl has single trailing slash - String b = baseUrl; - if(!b.endsWith("/")) b += "/"; - return b + p; -} - - -AsyncEventSource* eventProgress = nullptr; -void startFirmwareUpdateTask(AsyncEventSource* evProg) { - eventProgress = evProg; - if(Update_Task_Handle) { - ESP_LOGW(TAG, "Firmware update task already running"); - return; - } - xTaskCreate(firmwareUpdateTask, "FirmwareUpdate", 1024*8, NULL, 1, &Update_Task_Handle); -} - -void firmwareUpdateTask(void* parameter) { - static const char* TAG = "UpdateTask"; - AppUpdater* updater = nullptr; - - try { - loadUpdateJson(); - - // Initialize updater - updater = new AppUpdater(LittleFS, localVersion, updateUrl.c_str(), "manifest.json", "firmware.bin"); - updater->setProgressCallback(updateProgress); - - ESP_LOGI(TAG, "Starting update check from: %s", updateUrl.c_str()); - - // Check and perform updates - auto manifestResult = updater->checkManifest(); - - if (manifestResult != AppUpdater::ManifestCheckResult::UPDATE_AVAILABLE) { - // Handle different error cases - std::string errorMsg; - switch (manifestResult) { - case AppUpdater::ManifestCheckResult::ERROR_FETCH_FAILED: - errorMsg = "Failed to fetch manifest"; - break; - case AppUpdater::ManifestCheckResult::ERROR_TOO_LARGE: - errorMsg = "Manifest file too large"; - break; - case AppUpdater::ManifestCheckResult::ERROR_PARSE_FAILED: - errorMsg = "Failed to parse manifest"; - break; - case AppUpdater::ManifestCheckResult::ERROR_NO_FILES_SECTION: - errorMsg = "Manifest missing files section"; - break; - case AppUpdater::ManifestCheckResult::ERROR_NO_VERSION: - errorMsg = "Manifest missing version section"; - break; - case AppUpdater::ManifestCheckResult::VERSION_CURRENT: - errorMsg = "Current version is up to date"; - // This is not actually an error - ESP_LOGI(TAG, "No update needed: %s", errorMsg.c_str()); - throw std::runtime_error(errorMsg); - break; - default: - errorMsg = "Unknown manifest check error"; - } - throw std::runtime_error(errorMsg); - } - - if (updater->IsUpdateAvailable()) { - ESP_LOGI(TAG, "Update available, updating files..."); - - if (!updater->updateFilesArray()) { - throw std::runtime_error("Failed to update files"); - } - - ESP_LOGI(TAG, "Updating firmware..."); - if (!updater->updateApp()) { - throw std::runtime_error("Failed to update firmware"); - } - ESP_LOGI(TAG, "Update successful, restarting..."); - - sendUpdateMessage("Restarting ", true, 100); - vTaskDelay(2000); - - ESP.restart(); - - } - - } catch (const std::exception& e) { - ESP_LOGE(TAG, "Update failed: %s", e.what()); - } - delete updater; - Update_Task_Handle = NULL; - vTaskDelete(NULL); -} - -void startVersionCheckTask() { - if(versionCheckTask_Handle != NULL) { - ESP_LOGW(TAG, "Version Check Tak already running"); - return; - } - xTaskCreate(versionCheckTask, "VersionCheckTask", 1024*8, NULL, 1, &versionCheckTask_Handle); -} - -void versionCheckTask(void* parameter){ - if(updateUrl == ""){ - loadUpdateJson(); - } - AppUpdater updater(LittleFS, localVersion, updateUrl.c_str(), "manifest.json", "firmware.bin"); - - auto manifestResult = updater.checkManifest(); - - if (manifestResult == AppUpdater::ManifestCheckResult::UPDATE_AVAILABLE || - manifestResult == AppUpdater::ManifestCheckResult::VERSION_CURRENT) { - otaVersion = updater.otaVersion; // capture remote - ESP_LOGI(TAG, "Version check: remote=%s", otaVersion.toString().c_str()); - } else { - ESP_LOGE(TAG, "Version check: manifest check failed with code %d", static_cast(manifestResult)); - } - - versionCheckTask_Handle = NULL; - vTaskDelete(NULL); -} - -void loadUpdateJson(void) { - try { - ESP_LOGD(TAG, "loadUpdateJaon function..."); - if(updateUrl == "") { - String updateJsonPath = "/system/update.json"; - - // Read and parse update.json - File file = LittleFS.open(updateJsonPath); - if (!file) { - throw std::runtime_error("Failed to open update.json"); - } - - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - - if (error) { throw std::runtime_error("Failed to parse update.json"); } - - // Get update configuration - JsonObject jObj = doc.as(); - String folderName = jsonConstrainString(TAG, jObj, "folder", "latest/"); - String baseUrl = jsonConstrainString(TAG, jObj, "baseurl", "https://s3-minio.boothwizard.com/boothifier/"); - updateUrl = baseUrl + folderName; - - ESP_LOGD(TAG, "updateUrl: %s", updateUrl.c_str()); - } - } catch (const std::exception& e) { - ESP_LOGE(TAG, "Update failed: %s", e.what()); - } -} - -void updateProgress(AppUpdater::UpdateStatus newStatus, int percentage, const char* message = nullptr) { - - char buffer[128]; - const char* msg; - bool isComplete = false; - - const char* safeMsg = message ? message : ""; - switch (newStatus) { - case AppUpdater::UpdateStatus::IDLE: - snprintf(buffer, sizeof(buffer), "Update idle"); - msg = buffer; - break; - case AppUpdater::UpdateStatus::MESSAGE: - msg = message ? message : ""; - break; - case AppUpdater::UpdateStatus::DOWNLOADING: - snprintf(buffer, sizeof(buffer), "%s: Download progress: %d%%", safeMsg, percentage); - msg = buffer; - break; - case AppUpdater::UpdateStatus::VERIFYING: - snprintf(buffer, sizeof(buffer), "%s: Verifying update: %d%%", safeMsg, percentage); - msg = buffer; - break; - case AppUpdater::UpdateStatus::FILE_SKIPPED: - snprintf(buffer, sizeof(buffer), "%s: File Skipped, up to date", safeMsg); - msg = buffer; - break; - case AppUpdater::UpdateStatus::FILE_SAVED: - snprintf(buffer, sizeof(buffer), "%s: File Saved", safeMsg); - msg = buffer; - break; - case AppUpdater::UpdateStatus::MD5_FAILED: - snprintf(buffer, sizeof(buffer), "%s: MD5 Verification Failed", safeMsg); - msg = buffer; - break; - case AppUpdater::UpdateStatus::COMPLETE: - snprintf(buffer, sizeof(buffer), "Firmware Update Complete!!!"); - msg = buffer; - isComplete = true; - break; - case AppUpdater::UpdateStatus::ERROR: - snprintf(buffer, sizeof(buffer), "Error!: %s", safeMsg); - msg = buffer; - break; - default: - snprintf(buffer, sizeof(buffer), "Unknown update status: %d", (int)newStatus); - msg = buffer; - break; - } - - ESP_LOGI(TAG, "%s", msg); - sendUpdateMessage(msg, isComplete, percentage); -} - -void sendUpdateMessage(const char* message, bool complete, int progress = -1) { - - if(eventProgress && eventProgress->count() > 0) { - // This is for the web client and not the BLE client - JsonDocument jsonDoc; - jsonDoc["message"] = message; - jsonDoc["complete"] = complete; - jsonDoc["progress"] = progress; - String strMessage; - serializeJson(jsonDoc, strMessage); - eventProgress->send(strMessage.c_str(), "update", millis()); - } - else{ - ESP_LOGW(TAG, "No clients connected to event source"); - } - - bleUpgrade_send_message(message); -} - -// (Removed duplicate global checkManifest; AppUpdater::checkManifest used instead) - -/* -void setup() { - Serial.begin(115200); - - // Initialize WiFi connection first - // ... WiFi connection code ... - - // Initialize filesystem - if(!LittleFS.begin()) { - Serial.println("LittleFS Mount Failed"); - return; - } - - // Create updater instance with: - // - Current version: "1.0.0" - // - Update server URL: "https://my-update-server.com/" - // - Filesystem: LittleFS - AppUpdater updater("1.0.0", "https://storage.googleapis.com/boothifier/latest/", LittleFS); - - // Set progress callback - updater.setProgressCallback([](int progress) { - Serial.printf("Update progress: %d%%\n", progress); - }); - - // Check and update firmware - if (updater.checkAndUpdate()) { - Serial.println("Update successful! Rebooting..."); - ESP.restart(); - } - - // Update specific files from manifest - int updatedFiles = updater.updateFilesFromManifest("test_update.json"); - Serial.printf("Updated %d files\n", updatedFiles); -} - -*/ \ No newline at end of file diff --git a/temporary/Temp/ATALights2.cpp b/temporary/Temp/ATALights2.cpp deleted file mode 100644 index d64a258..0000000 --- a/temporary/Temp/ATALights2.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#include "ATALights.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include -#include "Animations.h" -#include -#include - - -static const char* tag = "strips"; - -// Define constants for maximum LEDs -#define MAX_LEDS 300 // Adjust based on your LED requirements - -// Create pointers for NeoPixelBus objects -void* strip1 = nullptr; -void* strip2 = nullptr; - -TaskHandle_t Animation_Task_Handle; - -// Runtime configuration variables -int numLeds1 = 0, numLeds2 = 0; // Number of LEDs for each strip -int dataPin1 = -1, dataPin2 = -1; // Data pins for each strip -String chipType1, chipType2; // Chip types (e.g., WS2812, SK6812, TM1814) -String colorOrder1, colorOrder2; // Color orders (e.g., GRB, RGB, BGR) - - -void Init_Lights_Task(void){ - - xTaskCreatePinnedToCore(Lights_Control_Task, "LumaMaster_Task", 1024*6, NULL, 1, &Animation_Task_Handle, CONFIG_ARDUINO_RUNNING_CORE); - ESP_LOGI(tag, "Lights Task Created..."); - - - // Example runtime configuration for two strips - dataPin1 = 5; // Pin for Strip 1 - numLeds1 = 150; // Number of LEDs on Strip 1 - chipType1 = "WS2812"; // Chip type for Strip 1 - colorOrder1 = "GRB"; // Color order for Strip 1 - - dataPin2 = 18; // Pin for Strip 2 - numLeds2 = 100; // Number of LEDs on Strip 2 - chipType2 = "WS2812"; // Chip type for Strip 2 - colorOrder2 = "RGB"; // Color order for Strip 2 - - // Dynamically initialize the strips - strip1 = initializeStrip(dataPin1, numLeds1, chipType1, colorOrder1); - strip2 = initializeStrip(dataPin2, numLeds2, chipType2, colorOrder2); - - - // Start the strips if initialized - if (strip1) static_cast*>(strip1)->Begin(); - if (strip2) static_cast*>(strip2)->Begin(); -} - - -void Animation_Loop_Exit(void){ - if( Animation_Task_Handle ){ - xTaskNotifyGive( Animation_Task_Handle ); - } -} - - -void LightsON(void){ - FastLED.show(); -} - - -void LightsOff(void){ - FastLED.clear(); - FastLED.show(); -} - - - -inline void setPixel1(int pixelIndex, const CRGB col) { - register uint16_t x = pixelIndex + ledSettings[0].shift; - // If strip.effSize is power of 2, use faster bit masking - if ((ledSettings[0].effSize & (ledSettings[0].effSize - 1)) == 0) { - x = (x < 0) ? ((x + ledSettings[0].effSize) & (ledSettings[0].effSize - 1)) : (x & (ledSettings[0].effSize - 1)); - leds1[(x + ledSettings[0].offset) & (ledSettings[0].effSize - 1)] = col; - } else { - // For non-power-of-2 sizes, still need modulo - x = (x < 0) ? ((x + ledSettings[0].effSize) % ledSettings[0].effSize) : (x % ledSettings[0].effSize); - leds1[(x + ledSettings[0].offset) % ledSettings[0].effSize] = col; - } -} - - -inline void setPixel2(int pixelIndex, const CRGB col) { - register uint16_t x = pixelIndex + ledSettings[1].shift; - // If strip.effSize is power of 2, use faster bit masking - if ((ledSettings[1].effSize & (ledSettings[1].effSize - 1)) == 0) { - x = (x < 0) ? ((x + ledSettings[1].effSize) & (ledSettings[1].effSize - 1)) : (x & (ledSettings[1].effSize - 1)); - leds2[(x + ledSettings[1].offset) & (ledSettings[1].effSize - 1)] = col; - } else { - // For non-power-of-2 sizes, still need modulo - x = (x < 0) ? ((x + ledSettings[1].effSize) % ledSettings[1].effSize) : (x % ledSettings[1].effSize); - leds2[(x + ledSettings[1].offset) % ledSettings[1].effSize] = col; - } -} - - -void Lights_Control_Task_Resume(void){ - vTaskResume(Animation_Task_Handle); -} - -void Lights_Control_Task(void *parameters){ - - ESP_LOGD(tag, "Lights Control Task Entered..."); - vTaskSuspend(NULL); - ESP_LOGD(tag, "Lights Control Task Resumed..."); - vTaskDelay(2000); - fill_solid(leds1, ledSettings[0].size-1, CRGB::Blue); - FastLED.show(); - vTaskDelay(5000); - - while(true){ - Animation_Loop(2000, [&]() { - ESP_LOGD(tag, "Looping...."); - - // Example animation: Alternate colors between strips - setStripColor>(strip1, numLeds1, RgbColor(255, 0, 0)); // Red for Strip 1 - setStripColor>(strip2, numLeds2, RgbColor(0, 255, 0)); // Green for Strip 2 - delay(1000); - - setStripColor>(strip1, numLeds1, RgbColor(0, 0, 255)); // Blue for Strip 1 - setStripColor>(strip2, numLeds2, RgbColor(255, 255, 0)); // Yellow for Strip 2 - delay(1000); - }); - - /* - uint8_t animMode = 1; - switch(animMode){ - case 0: - break; - case 1: - break; - } - */ - } -} - - -void Init_FastLED_Strip(CRGB* leds, uint8_t pin, int size, EOrder rgbOrder, const String& chipType) { - - - -} - -// Function to initialize a strip dynamically (Non-SPI chipsets only) -void* initializeStrip(int dataPin, int numLeds, const String& chipType, const String& colorOrder) { - if (chipType == "WS2812" || chipType == "SK6812") { - if (colorOrder == "GRB") { - return new NeoPixelBus(numLeds, dataPin); - } else if (colorOrder == "RGB") { - return new NeoPixelBus(numLeds, dataPin); - } else if (colorOrder == "BGR") { - return new NeoPixelBus(numLeds, dataPin); - } - } - Serial.println("Unsupported chipset or color order!"); - return nullptr; -} - -// Function to set all LEDs of a strip to a specific color -template -void setStripColor(void* strip, int numLeds, RgbColor color) { - if (strip) { - T* actualStrip = static_cast(strip); - for (int i = 0; i < numLeds; i++) { - actualStrip->SetPixelColor(i, color); - } - actualStrip->Show(); - } -} - - diff --git a/temporary/Temp/BLE-FlashStick-Service.h b/temporary/Temp/BLE-FlashStick-Service.h deleted file mode 100644 index 29260e8..0000000 --- a/temporary/Temp/BLE-FlashStick-Service.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -#include -#include diff --git a/temporary/Temp/BLE-FlaskStick-Service.cpp b/temporary/Temp/BLE-FlaskStick-Service.cpp deleted file mode 100644 index 2172ffc..0000000 --- a/temporary/Temp/BLE-FlaskStick-Service.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include "BLE-FlashStick-Service.h" -#include "WiFi.h" -#include "my_wifi.h" -#include "global.h" -#include "AppUpgrade.h" -#include "AppVersion.h" - -static const char *tag = "BLE_FlashStickService"; - -#define UPGRADE_SERVICE_UUID "abcdef03-2345-6789-1234-56789abcdef0" -#define UPGRADE_CHARACTERISTIC1_UUID "abcdef03-2345-6789-1234-56789abcdef1" - -NimBLEService *pUpgradeService = nullptr; -NimBLECharacteristic *pUpgradeCharacteristic1 = nullptr; - -enum WIFI_STAT : byte { WIFI_DISCONNECTED=0, WIFI_BAD_CREDS=1, WIFI_NO_AP=2, WIFI_CONNECTED=3 }; - -struct FLASHSTICK_PACKET { - bool reistered = false; - char msg[16] = "Hello..."; -}flashstickPacket; - - -// Class for handling server events -class ServerCallbacks : public NimBLEServerCallbacks { - void onConnect(NimBLEServer* pServer) override { - ESP_LOGI(tag, "Flash-Stick connected"); - } - - void onDisconnect(NimBLEServer* pServer) override { - ESP_LOGI(tag, "Flash-Stick disconnected"); - } -}; - - -// Class for handling characteristic events -class UpgradeChar_Callbacks : public NimBLECharacteristicCallbacks { - - void onWrite(NimBLECharacteristic *pCharacteristic) override { - std::string value = pCharacteristic->getValue(); - ESP_LOGD(tag, "Upgrade Char written with value: %s", value.c_str()); - - if (value.compare(0, 12, "wifi-connect") == 0) { // Update WiFi credentials - JsonDocument doc; - deserializeJson(doc, value.substr(13)); - JsonObject wifiJson = doc.as(); - String ssid = wifiJson["ssid"].as(); - String pass = wifiJson["pass"].as(); - ESP_LOGI(tag, "Wifi Credentials: %s, %s", ssid.c_str(), pass.c_str()); - - bool status = StartWifiConnectTask(ssid, pass); - if(status == true){ - updatePacket.wifiStatus = WIFI_DISCONNECTED; - updatePacket.wifiOnline = false; - updatePacket.wifiIP[0] = updatePacket.wifiIP[1] = updatePacket.wifiIP[2] = updatePacket.wifiIP[3] = 0; - }else{ - ESP_LOGI(tag, "Failed to start WiFi connection task"); - } - } - else if (value.compare("version-check") == 0) { // Check if new version is available - ESP_LOGI(tag, "Version check command received: newVersion=%d.%d.%d", otaVersion.major(), otaVersion.minor(), otaVersion.patch()); - if(updatePacket.newVersion[0] == 0){ - startVersionCheckTask(); // start the task and done - }else{ - ESP_LOGI(tag, "Version already checked"); - } - } - else if (value.compare("upgrade-start") == 0) { // Start OTA update - ESP_LOGI(tag, "Start OTA update command received"); - startFirmwareUpdateTask(nullptr); // start the task - } - else if (value.compare("rename-device") == 0) { // Start renaming device - ESP_LOGI(tag, "Start renane device command received"); - } - else { - ESP_LOGW(tag, "Unknown command received: %s", value.c_str()); - } - } - - void onRead(NimBLECharacteristic *pCharacteristic) override { - updatePacket.wifiOnline = InternetAvailable; - if(WiFi.status() == WL_CONNECTED){ - updatePacket.wifiStatus = WIFI_CONNECTED; - if(updatePacket.wifiIP[0] == 0){ - updatePacket.wifiIP[0] = WiFi.localIP()[0]; - updatePacket.wifiIP[1] = WiFi.localIP()[1]; - updatePacket.wifiIP[2] = WiFi.localIP()[2]; - updatePacket.wifiIP[3] = WiFi.localIP()[3]; - } - }else{ - updatePacket.wifiStatus = WIFI_DISCONNECTED; - if(updatePacket.wifiIP[0] > 0){ - updatePacket.wifiIP[0] = 0; - updatePacket.wifiIP[1] = 0; - updatePacket.wifiIP[2] = 0; - updatePacket.wifiIP[3] = 0; - } - } - - //update version - if(otaVersion.major() != 0){ - ESP_LOGI(tag, "Updated new version: major=%d, minor=%d, patch=%d", otaVersion.major(), otaVersion.minor(), otaVersion.patch()); - updatePacket.newVersion[0] = otaVersion.major(); - updatePacket.newVersion[1] = otaVersion.minor(); - updatePacket.newVersion[2] = otaVersion.patch(); - } - - pCharacteristic->setValue(reinterpret_cast(&updatePacket), sizeof(updatePacket)); - ESP_LOGI(tag, "Upgrade Char read"); - } -}; - - -void bleUpgrade_send_message(String s){ - if(pUpgradeCharacteristic2){ - if (s != nullptr) { - pUpgradeCharacteristic2->setValue(s); - pUpgradeCharacteristic2->notify(); - } else { - ESP_LOGW(tag, "Null string passed to bleUpgrade_send_message"); - } - } -} - - -void Init_UpgradeBLEService(NimBLEServer *pServer){ - - // Create Upgrade BLE Service - pUpgradeService= pServer->createService( UPGRADE_SERVICE_UUID ); - - pUpgradeCharacteristic1 = pUpgradeService->createCharacteristic( - UPGRADE_CHARACTERISTIC1_UUID, - NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::NOTIFY - ); - - // Register the callback with the characteristic - pUpgradeCharacteristic1->setCallbacks(new UpgradeChar_Callbacks()); - ESP_LOGI(tag, "Upgrade callback registered!"); - - - pUpgradeCharacteristic2 = pUpgradeService->createCharacteristic( - UPGRADE_CHARACTERISTIC2_UUID, - NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY - ); - - // Register the callback with the characteristic - pUpgradeCharacteristic2->setCallbacks(new UpgradeChar_Callbacks()); - ESP_LOGI(tag, "Upgrade callback registered!"); - - pUpgradeService->start(); - - NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising(); - pAdvertising->addServiceUUID( UPGRADE_SERVICE_UUID ); // Advertise service UUID - - -} - diff --git a/temporary/Temp/BTSerial.cpp b/temporary/Temp/BTSerial.cpp deleted file mode 100644 index 4295c4b..0000000 --- a/temporary/Temp/BTSerial.cpp +++ /dev/null @@ -1,240 +0,0 @@ -#include "BTSerial.h" -#include -#include -#include -#include -#include -#include -#include "command_processor.h" -#include "led_strip.h" -#include "global.h" -#include "JsonConstrain.h" -#include "my_buzzer.h" -#include "common/led_animation.h" - - -static const char* tag = "ble"; -TaskHandle_t BTSerial_Task_Handle; -bool BTDeviceConnected = false; - -BLEServer *pServer = NULL; -BLECharacteristic * pTxCharacteristic; -BLECharacteristic * pRxCharacteristic; -bool oldDeviceConnected = false; -uint8_t txValue = 0; - -// See the following for generating UUIDs: -// https://www.uuidgenerator.net/ -#define SERVICE_UUID_DEF "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID -#define CHARACTERISTIC_UUID_RX_DEF "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" -#define CHARACTERISTIC_UUID_TX_DEF "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" - -String BLEDeviceName; -String BLEKey; -String SERVICE_UUID; -String CHARACTERISTIC_UUID_RX; -String CHARACTERISTIC_UUID_TX; - -#define replyActive true - - -void Init_BTSerial(void) -{ - File file = LittleFS.open("/cfg/ble.json"); - if(!file){ - ESP_LOGE(tag, "Error opening ble.json..."); - } - else{ - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - if(error){ ESP_LOGE(tag, "ble.json deserialize error!.."); return;} - - JsonObject bleJson = doc.as(); - - // if(jsonConstrainBool(bleJson, "en", false)){ - SERVICE_UUID = jsonConstrainString(tag, bleJson, "service-uuid", SERVICE_UUID_DEF); - ESP_LOGD(tag, "SERVICE_UUID: %s", SERVICE_UUID.c_str()); - - CHARACTERISTIC_UUID_RX = jsonConstrainString(tag, bleJson, "char-uuid-rx", CHARACTERISTIC_UUID_RX_DEF); - ESP_LOGD(tag, "Char UUID RX: %s", CHARACTERISTIC_UUID_RX.c_str()); - - CHARACTERISTIC_UUID_TX = jsonConstrainString(tag, bleJson, "char-uuid-tx", CHARACTERISTIC_UUID_TX_DEF); - ESP_LOGD(tag, "Char UUID TX: %s", CHARACTERISTIC_UUID_TX.c_str()); - - BLEDeviceName = jsonConstrainString(tag, bleJson, "device-name", "ATA_COMM"); - String hexStr = String(chipInfo.macByte[0], HEX); - hexStr.toUpperCase(); - BLEDeviceName += '_'; - BLEDeviceName += hexStr; - - BLEKey = jsonConstrainString(tag, bleJson, "key", "123456"); - int core = jsonConstrain(tag, bleJson, "core", 0, 1, 0); - ESP_LOGD(tag, "BLE SSID: %s, key: %s, core: %d", BLEDeviceName.c_str(),BLEKey.c_str(), core); - - xTaskCreatePinnedToCore(BTSerial_Task, "BTSerial_Task", 12000, NULL, 1, &BTSerial_Task_Handle, core); - //} - } -} - -/** None of these are required as they will be handled by the library with defaults. ** - ** Remove as you see fit for your needs */ -class MyServerCallbacks: public BLEServerCallbacks { - void onConnect(BLEServer* pServer) { - BTDeviceConnected = true; - //BLEDevice::startAdvertising();//adding this line allows for multiple simultaneous BLE connections - }; - /* - void onConnect(BLEServer* pServer, BLEClient* pClient) { - BTDeviceConnected = true; - BLEAddress connectedAddress = pClient->getPeerAddress(); - Log.traceln("Client connected: %s", connectedAddress.toString().c_str()); - } - */ - - void onDisconnect(BLEServer* pServer) { - BTDeviceConnected = false; - } - /***************** New - Security handled here ******************** - ****** Note: these are the same return values as defaults ********/ - uint32_t onPassKeyRequest(){ - ESP_LOGD(tag, "Server PassKeyRequest"); - return 123456; - } - - bool onConfirmPIN(uint32_t pass_key){ - ESP_LOGD(tag, "The passkey YES/NO number: %d", pass_key); - return true; - } - - void onAuthenticationComplete(ble_gap_conn_desc desc){ - ESP_LOGD(tag, "Starting BLE work!"); - } - /*******************************************************************/ -}; - -#define MAX_PACKET_PARAMS 8 -int packet_data[MAX_PACKET_PARAMS]; -int paramCount = 0; -class MyCallbacks: public BLECharacteristicCallbacks -{ - void onWrite(BLECharacteristic *pCharacteristic) - { - std::string rxValue = pCharacteristic->getValue(); - - ESP_LOGD(tag, "raw: %s", rxValue.c_str()); - if(!rxValue.empty() && ((rxValue[0] == '$') || rxValue[0] == '%')){ - extractCommand(&rxValue[0], packet_data, ¶mCount); // delimited command - - // Call Animation Index Update - if(packet_data[0] == 100){ - int cntDown = 0; - if(packet_data[2]){ - cntDown = packet_data[2]; - } - animProps.event[packet_data[1]].countDown = cntDown; - animProps.event[packet_data[1]].type = EV_NORMAL; - PostNewEvent(animProps.event[packet_data[1]]); - }else{ - // TODO: Process other Bluetooth commands - } - - if(replyActive){ - rxValue[0] = '%'; - pTxCharacteristic->setValue(rxValue); - pTxCharacteristic->notify(); - } - // print params - ESP_LOGD(tag, "packet: %c%d, %d", rxValue[0], packet_data[0], packet_data[1]); - } - } -}; - -void extractCommand(char* packet, int* data, int* count) -{ - int base = 10; - //if(*packet == '#'){ - // base = 16; - //} - packet++; - - char* token = strtok(packet, ",\n"); - int8_t index = 0; - - while (token != NULL && index < MAX_PACKET_PARAMS) { - data[index] = strtol(token, NULL, base); - index++; - token = strtok(NULL, ",\n"); - } - *count = index; -} - -void BTSerial_Task(void *parameters){ - vTaskDelay(1000); - // Extend watchdog timer - esp_task_wdt_init(5, false); - - // Create the BLE Device. - BLEDevice::init(BLEDeviceName.c_str()); - - // Create the BLE Server - pServer = BLEDevice::createServer(); - pServer->setCallbacks(new MyServerCallbacks()); - - // Create the BLE Service - BLEService *pService = pServer->createService((const char*)SERVICE_UUID.c_str()); - - // Create a BLE Characteristic - pTxCharacteristic = pService->createCharacteristic( (const char*)CHARACTERISTIC_UUID_TX.c_str(), NIMBLE_PROPERTY::NOTIFY ); - /*************************************************** - NOTE: DO NOT create a 2902 descriptor, it will be created auto.. if notifications - or indications are enabled on a characteristic. - - pCharacteristic->addDescriptor(new BLE2902()); - ****************************************************/ - pRxCharacteristic = pService->createCharacteristic( (const char*)CHARACTERISTIC_UUID_RX.c_str(), NIMBLE_PROPERTY::WRITE ); - pRxCharacteristic->setCallbacks(new MyCallbacks()); - // Start the service - pService->start(); - - // Start advertising - vTaskDelay(100); - pServer->getAdvertising()->start(); - ESP_LOGV(tag, "Waiting for a client..."); - ANIMATION_EVENT newEvent; - for(;;){ - //if (BTDeviceConnected) { - //pTxCharacteristic->setValue(&txValue, 1); - //pTxCharacteristic->notify(); - //txValue++; - //vTaskDelay(100); // bluetooth stack will go into congestion, if too many packets are sent - //} - - // disconnecting - if (!BTDeviceConnected && oldDeviceConnected) { - vTaskDelay(750); // give the bluetooth stack the chance to get things ready - pServer->startAdvertising(); // restart advertising - oldDeviceConnected = BTDeviceConnected; - newEvent.animIndex = POP_BLE_DISC; - newEvent.type = EV_INJECT; - PostNewEvent(newEvent); - ESP_LOGI(tag, "Client disconnected..."); - ESP_LOGI(tag, "Advertising again..."); - Buzzer_Play_Tune(TUNE_BLE_DISCONNECTED); - } - - // connecting - if (BTDeviceConnected && !oldDeviceConnected) { - // do stuff here on connecting - oldDeviceConnected = BTDeviceConnected; - newEvent.animIndex = POP_BLE_CONN; - newEvent.type = EV_INJECT; - PostNewEvent(newEvent); - ESP_LOGI(tag, "Client connected..."); - Buzzer_Play_Tune(TUNE_BLE_CONNECTED); - } - - vTaskDelay(200); - } - -} \ No newline at end of file diff --git a/temporary/Temp/BTSerial.h b/temporary/Temp/BTSerial.h deleted file mode 100644 index 1691151..0000000 --- a/temporary/Temp/BTSerial.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _BTSERIAL_H -#define _BTSERIAL_H - -#include - - -extern bool BTDeviceConnected; -extern String BLEDeviceName; - -void Init_BTSerial(void); - -void BTSerial_Task(void *parameters); - -void extractCommand(char* packet, int* data, int* count); - -#endif \ No newline at end of file diff --git a/temporary/Temp/EventBoxTest.html b/temporary/Temp/EventBoxTest.html deleted file mode 100644 index 114f15e..0000000 --- a/temporary/Temp/EventBoxTest.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - -Event Container - - - -
-
-
- - - -
-
- - - - diff --git a/temporary/Temp/GenUpdate.py b/temporary/Temp/GenUpdate.py deleted file mode 100644 index 51c40b3..0000000 --- a/temporary/Temp/GenUpdate.py +++ /dev/null @@ -1,164 +0,0 @@ -import os -import shutil -import hashlib -import json - -def copy_folder_to_destination(src_path, dest_path, skip_dirs=None, skip_files=None): - # Ensure the destination directory exists - os.makedirs(os.path.dirname(dest_path), exist_ok=True) - - # Remove existing folder if present - if os.path.exists(dest_path): - shutil.rmtree(dest_path) - - # Create destination directory - os.makedirs(dest_path) - - # Walk through source directory - for root, dirs, files in os.walk(src_path): - # Remove directories to skip from dirs list - if skip_dirs: - dirs[:] = [d for d in dirs if d not in skip_dirs] - - # Calculate relative path - rel_path = os.path.relpath(root, src_path) - dest_dir = os.path.join(dest_path, rel_path) - - # Create corresponding destination directory - os.makedirs(dest_dir, exist_ok=True) - - # Copy files that aren't in skip_files - for file in files: - if skip_files and file in skip_files: - continue - src_file = os.path.join(root, file) - dest_file = os.path.join(dest_dir, file) - shutil.copy2(src_file, dest_file) - -def calculate_md5(file_path): - hash_md5 = hashlib.md5() - with open(file_path, "rb") as f: - for chunk in iter(lambda: f.read(4096), b""): - hash_md5.update(chunk) - return hash_md5.hexdigest() - -def get_file_size(file_path): - return os.path.getsize(file_path) - -def update_json_file(json_array, folder_path): - # Create new data array for files - file_array = [] - - # Walk through the copied folder and collect file details - for root, _, files in os.walk(folder_path): - for file in files: - file_path = os.path.join(root, file) - relative_path = os.path.relpath(file_path, folder_path) - - # Replace backslashes with forward slashes - relative_path = relative_path.replace('\\', '/') - - file_entry = { - "remote": os.path.join("data/", relative_path), - "local": os.path.join("/", relative_path), - "md5": calculate_md5(file_path), - "size": get_file_size(file_path) - } - file_array.append(file_entry) - - # Replace the contents of the input json_array with new data - json_array.clear() - json_array.extend(file_array) - -def update_files(src_path, dest_path, skip_dirs=None, skip_files=None): - # Check if the source folder exists - if not os.path.isdir(src_path) or not os.path.isdir(dest_path): - print("Invalid folder path!") - return - - # Copy all data contents - copy_folder_to_destination(src_path, dest_path, skip_dirs, skip_files) - print("Folder copied successfully.") - - - -def main(): - - here_path = os.path.dirname(os.path.abspath(__file__)) - project_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - - # Path of the folder to copy (you can modify this) - src_folder_name = "data" - src_path = os.path.join(project_path, src_folder_name) - #print(f"source path: {src_path}") - - # Path of the destination folder - dest_folder_name = "firmware_update\\latest\\data" - dest_path = os.path.join(project_path, dest_folder_name) - #print(f"destination path: {dest_path}") - - # Path of the firmware binary file - bin_name = ".pio\\build\\esp32s3dev\\firmware.bin" - - # Skip these directories - skip_dirs = ["boards", "booths"] - - # Skip these files - skip_files = ["wifi.json", "system.json", "luma-stiks.json", ] - - - update_files = input("Do you want to update the files? (y/n): ") - - # *********************** Copy Data Files *********************** - if update_files.lower() == "y": - update_files(src_path, dest_path, skip_dirs, skip_files) - - - # *********************** Copy Binary file *********************** - update_firmware = input("Do you want to update the firmware? (y/n): ") - if update_firmware.lower() == "y": - # Copy firmware.bin to the destination - bin_path = os.path.join(project_path, bin_name) - shutil.copy(bin_path, here_path) - #print(f"firmware path: {bin_path}") - print("firmware.bin copied successfully.") - - - - # *********************** Process update.json *********************** - # Update the JSON file - json_path = os.path.join(here_path, "update.json") - print(f"json path: {json_path}") - - # Read existing JSON - with open(json_path, "r") as f: - try: - json_doc = json.load(f) - except json.JSONDecodeError: - print("Invalid JSON file!") - return - - # process the files array - #if update_files.lower() == "y": - json_files_array = json_doc["files"] - update_json_file(json_files_array, dest_path) - #print(f"Folder {os.path.basename(src_path)} processed successfully.") - - - # *********************** Process firmwware.bin in update.json *********************** - # process the firmware - if update_firmware.lower() == "y": - json_firmware = json_doc["firmware"] - firmware_path = os.path.join(here_path, "firmware.bin") - json_firmware["md5"] = calculate_md5(firmware_path) - json_firmware["size"] = get_file_size(firmware_path) - - - # Write updated JSON - with open(json_path, "w") as f: - json.dump(json_doc, f, indent=4) - - print("Update JSON files created successfully.") - -if __name__ == "__main__": - main() diff --git a/temporary/Temp/MyNeoPixelBus.cpp b/temporary/Temp/MyNeoPixelBus.cpp deleted file mode 100644 index 74a81f6..0000000 --- a/temporary/Temp/MyNeoPixelBus.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include - -// Define constants for maximum LEDs -#define MAX_LEDS 300 // Adjust based on your LED requirements - -// Wrapper class for dynamic LED strips -class DynamicLedStrip { -private: - void* strip; // Pointer to the NeoPixelBus object - int numLeds; // Number of LEDs - String colorOrder; // Color order (for reference) - -public: - DynamicLedStrip() : strip(nullptr), numLeds(0), colorOrder("") {} - - // Initialize the LED strip - void initialize(int dataPin, int numLeds, const String& chipType, const String& colorOrder) { - this->numLeds = numLeds; - this->colorOrder = colorOrder; - - if (chipType == "WS2812" || chipType == "SK6812") { - if (colorOrder == "GRB") { - strip = new NeoPixelBus(numLeds, dataPin); - } else if (colorOrder == "RGB") { - strip = new NeoPixelBus(numLeds, dataPin); - } else if (colorOrder == "BGR") { - strip = new NeoPixelBus(numLeds, dataPin); - } - } - - if (strip) { - static_cast*>(strip)->Begin(); - } else { - Serial.println("Unsupported chipset or color order!"); - } - } - - // Set all LEDs to a specific color - void setColor(const RgbColor& color) { - if (strip) { - for (int i = 0; i < numLeds; i++) { - static_cast*>(strip)->SetPixelColor(i, color); - } - static_cast*>(strip)->Show(); - } - } -}; \ No newline at end of file diff --git a/temporary/Temp/UploadToMinio.py b/temporary/Temp/UploadToMinio.py deleted file mode 100644 index 516301d..0000000 --- a/temporary/Temp/UploadToMinio.py +++ /dev/null @@ -1,337 +0,0 @@ -#!/usr/bin/env python3 -"""Upload firmware, manifest, and data assets to a MinIO (S3-compatible) bucket. - -Features preserved from original GCS script: - - Optional backup (copies existing objects under destination prefix to timestamped folder under backups/) - - Upload firmware.bin, update.json, and recursively mirror a data directory - - Cache-Control set to disable caching on clients - -Switches from google.cloud.storage to boto3 (S3 API) for MinIO compatibility. -""" -import os -import sys -import datetime -import json -from pathlib import Path - -try: - import boto3 - from botocore.exceptions import ClientError - from botocore.config import Config -except ImportError: - print("ERROR: boto3 is required. Install with: pip install boto3") - sys.exit(1) - -# ============================================================================= -# CONFIGURATION CONSTANTS (edit as needed or supply via environment variables) -# ============================================================================= - -CREATE_BACKUP = False -UPLOAD_FIRMWARE = False -UPLOAD_MANIFEST = True -UPLOAD_DATA = False - -# Bucket / endpoint configuration -BUCKET_NAME = os.getenv('MINIO_BUCKET', 'boothifier') -DESTINATION_DIR = os.getenv('MINIO_DEST_PREFIX', 'latest') # prefix inside bucket -BACKUPS_DIR = os.getenv('MINIO_BACKUPS_PREFIX', 'backups') - -LOCAL_ROOT_PATH = Path(__file__).parent.resolve() - -# Optional service account style JSON key (generated by MinIO Console). Expected fields: -# {"url":"https://minio.example.com/api/v1/service-account-credentials","accessKey":"...","secretKey":"...","api":"s3v4","path":"auto"} -MINIO_KEY_FILE = LOCAL_ROOT_PATH / 'minio-boothifier-key.json' - -# Defaults before loading file / env -_json_access = None -_json_secret = None -_json_url = None - -def _load_json_key(): - global _json_access, _json_secret, _json_url - try: - if MINIO_KEY_FILE.is_file(): - with open(MINIO_KEY_FILE, 'r', encoding='utf-8') as fh: - data = json.load(fh) - _json_access = data.get('accessKey') or None - _json_secret = data.get('secretKey') or None - _json_url = data.get('url') or None - except Exception as e: - print(f"WARN: Failed to load MinIO key file '{MINIO_KEY_FILE.name}': {e}") - -_load_json_key() - -def _derive_endpoint(url_value: str) -> str: - if not url_value: - return 'https://s3-minio.boothwizard.com' - # Remove known API suffix if present (/api/...) - # e.g. https://s3-minio.boothwizard.com/api/v1/service-account-credentials -> https://s3-minio.boothwizard.com - parts = url_value.split('/api/') - return parts[0] if parts else url_value - -# MinIO credentials with precedence: ENV > JSON file > fallback -MINIO_ENDPOINT = os.getenv('MINIO_ENDPOINT') or _derive_endpoint(_json_url) -MINIO_ACCESS_KEY = os.getenv('MINIO_ACCESS_KEY') or _json_access or 'CHANGE_ME_ACCESS' -MINIO_SECRET_KEY = os.getenv('MINIO_SECRET_KEY') or _json_secret or 'CHANGE_ME_SECRET' -MINIO_REGION = os.getenv('MINIO_REGION', 'us-east-1') # MinIO ignores but boto3 wants some value - - # Addressing / SSL options -MINIO_ADDRESSING = os.getenv('MINIO_ADDRESSING_STYLE', 'path').lower() # 'path' or 'virtual' -MINIO_VERIFY_SSL = os.getenv('MINIO_TLS_VERIFY', '1') not in ('0','false','no') -MINIO_DEBUG = os.getenv('MINIO_DEBUG', '0') in ('1','true','yes') -MINIO_ALLOW_VARIANTS = os.getenv('MINIO_ALLOW_ENDPOINT_VARIANTS', '0') in ('1','true','yes') # normally false with nginx redirect - -LOCAL_FIRMWARE_PATH = str(LOCAL_ROOT_PATH / 'latest' / 'firmware.bin') -LOCAL_MANIFEST_PATH = str(LOCAL_ROOT_PATH / 'latest' / 'update.json') -LOCAL_DATA_DIRECTORY = str(LOCAL_ROOT_PATH / 'latest' / 'data') - -# ============================================================================= -# HELPERS -# ============================================================================= - -def s3_client(): - """Create an S3 client pointed at MinIO endpoint, forcing path-style unless overridden, with short timeouts.""" - addressing = 'path' if MINIO_ADDRESSING not in ('virtual','auto') else 'virtual' - cfg = Config( - s3={'addressing_style': addressing}, - signature_version='s3v4', - connect_timeout=3, - read_timeout=5, - retries={'max_attempts': 2} - ) - if MINIO_DEBUG: - masked_key = (MINIO_ACCESS_KEY[:3] + '...' + MINIO_ACCESS_KEY[-3:]) if MINIO_ACCESS_KEY else 'None' - print(f"[DEBUG] Creating client: endpoint={MINIO_ENDPOINT} addressing={addressing} verifySSL={MINIO_VERIFY_SSL} region={MINIO_REGION} accessKey={masked_key}") - return boto3.client( - 's3', - endpoint_url=MINIO_ENDPOINT, - aws_access_key_id=MINIO_ACCESS_KEY, - aws_secret_access_key=MINIO_SECRET_KEY, - region_name=MINIO_REGION, - verify=MINIO_VERIFY_SSL, - config=cfg, - ) - -def _endpoint_variants(base: str): - """Return endpoint variants only if explicitly allowed; otherwise just the base (nginx handles forwarding).""" - if not MINIO_ALLOW_VARIANTS: - return [base] - # Fallback to previous expanded logic if variants are enabled - try: - variants = [] - if not base: - return variants - base = base.rstrip('/') - proto_sep = '://' - if proto_sep in base: - scheme, rest = base.split(proto_sep,1) - else: - scheme, rest = 'https', base - host_port = rest - if ':' in host_port: - host, port = host_port.split(':',1) - else: - host, port = host_port, '' - variants.append(f"{scheme}://{host_port}") - common_ports = ['9000','443','80'] - for p in common_ports: - if port != p: - variants.append(f"{scheme}://{host}:{p}") - alt_scheme = 'http' if scheme == 'https' else 'https' - variants.append(f"{alt_scheme}://{host_port}") - for p in common_ports: - if port != p: - variants.append(f"{alt_scheme}://{host}:{p}") - seen = set() - uniq = [] - for v in variants: - if v not in seen: - uniq.append(v) - seen.add(v) - return uniq - except Exception: - return [base] - -def create_validated_client(): - """Validate (or create) client using only provided endpoint unless variants enabled.""" - global MINIO_ENDPOINT - primary = MINIO_ENDPOINT - variants = _endpoint_variants(primary) or [primary] - errors = [] - probe_bucket = BUCKET_NAME # we will head the target bucket directly - for candidate in variants: - saved = MINIO_ENDPOINT - MINIO_ENDPOINT = candidate - if MINIO_DEBUG: - print(f"[DEBUG] Probing endpoint candidate: {candidate}") - try: - c = s3_client() - try: - c.head_bucket(Bucket=probe_bucket) - if MINIO_DEBUG: - print(f"[DEBUG] head_bucket succeeded on {candidate} for '{probe_bucket}'.") - return c - except ClientError as e: - msg = str(e) - # Acceptable if bucket not found (we can create later) - if any(code in msg for code in ('404', 'NoSuchBucket', 'NotFound')): - if MINIO_DEBUG: - print(f"[DEBUG] Bucket not found on {candidate} (expected if first deploy). Using this endpoint.") - return c - if 'API Requests must be made to API port' in msg: - errors.append(f"{candidate}: wrong port (console endpoint)") - else: - errors.append(f"{candidate}: {msg}") - MINIO_ENDPOINT = saved - except Exception as ex: - errors.append(f"{candidate}: {ex}") - MINIO_ENDPOINT = saved - continue - print("ERROR: Could not validate any endpoint candidate.") - for e in errors: - print(' - ' + e) - print("Provide correct API endpoint (e.g. https://host:9000) via MINIO_ENDPOINT env var.") - sys.exit(3) - -def list_objects(client, prefix: str): - """Generator yielding object keys under a prefix (non-recursive listing with pagination).""" - kwargs = {'Bucket': BUCKET_NAME, 'Prefix': prefix} - while True: - resp = client.list_objects_v2(**kwargs) - for obj in resp.get('Contents', []): - yield obj['Key'] - if not resp.get('IsTruncated'): - break - kwargs['ContinuationToken'] = resp['NextContinuationToken'] - -def normalize_prefix(p: str) -> str: - p = p.strip('/') - return p - -def join_key(*parts: str) -> str: - parts_clean = [p.strip('/') for p in parts if p is not None and p != ''] - return '/'.join(parts_clean) - -def backup_existing_files(client, destination_prefix: str, backups_prefix: str, backup_folder: str): - if not destination_prefix: - prefix = '' - else: - prefix = destination_prefix + '/' - print(f"Scanning existing objects under '{prefix}' for backup...") - for key in list_objects(client, prefix): - if backups_prefix and key.startswith(backups_prefix + '/'): # Skip prior backups - continue - # relative path within destination - relative = key[len(prefix):] if prefix and key.startswith(prefix) else key - backup_key = join_key(backups_prefix, backup_folder, relative) - print(f"Backup copy: {key} -> {backup_key}") - client.copy_object( - Bucket=BUCKET_NAME, - CopySource={'Bucket': BUCKET_NAME, 'Key': key}, - Key=backup_key, - MetadataDirective='COPY' - ) - -def upload_file(client, local_path: str, key: str, cache_control: str = 'private, max-age=0, no-transform'): - if not os.path.isfile(local_path): - print(f"WARN: File missing, skipping: {local_path}") - return - print(f"Upload: {local_path} -> s3://{BUCKET_NAME}/{key}") - extra_args = { 'CacheControl': cache_control } - client.upload_file(local_path, BUCKET_NAME, key, ExtraArgs=extra_args) - -def upload_directory(client, local_directory: str, destination_prefix: str): - if not os.path.isdir(local_directory): - print(f"WARN: Data directory missing: {local_directory}") - return - for root, _, files in os.walk(local_directory): - for fname in files: - full = os.path.join(root, fname) - rel = os.path.relpath(full, local_directory) - key = join_key(destination_prefix, rel) - upload_file(client, full, key) - -def ensure_bucket(client): - """Ensure bucket exists; provide diagnostics if HeadBucket returns 400/other errors.""" - try: - client.head_bucket(Bucket=BUCKET_NAME) - if MINIO_DEBUG: - print(f"[DEBUG] Bucket '{BUCKET_NAME}' exists.") - return - except ClientError as e: - code = e.response.get('Error', {}).get('Code') - status = e.response.get('ResponseMetadata', {}).get('HTTPStatusCode') - print(f"HeadBucket failed (code={code}, status={status}).") - - # List buckets for diagnostics - try: - resp = client.list_buckets() - bucket_names = [b['Name'] for b in resp.get('Buckets', [])] - print(f"Available buckets: {bucket_names or 'None'}") - except Exception as le: - print(f"WARN: list_buckets failed: {le}") - - if code in ('404', 'NoSuchBucket', 'NotFound'): - print(f"Bucket '{BUCKET_NAME}' not found. Attempting to create...") - try: - client.create_bucket(Bucket=BUCKET_NAME) - print(f"Created bucket '{BUCKET_NAME}'.") - return - except ClientError as ce: - print(f"ERROR: Cannot create bucket: {ce}") - sys.exit(2) - - if status == 400: - print("HINTS: \n - Verify endpoint URL (MINIO_ENDPOINT).\n - Ensure no trailing slash in endpoint.\n - Check that TLS verify matches server cert (set MINIO_TLS_VERIFY=0 to test).\n - Confirm bucket name is correct and DNS compatible.\n - Credentials may lack permission: verify access key policies.") - - # Retry once forcing path style if not already - if MINIO_ADDRESSING != 'path': - print("Retrying with path-style addressing...") - os.environ['MINIO_ADDRESSING_STYLE'] = 'path' - new_client = s3_client() - try: - new_client.head_bucket(Bucket=BUCKET_NAME) - print("Second attempt succeeded with path-style addressing.") - return - except ClientError as e2: - print(f"Second HeadBucket attempt failed: {e2}") - print(f"ERROR: head_bucket ultimately failed: {e}") - sys.exit(2) - -# ============================================================================= -# MAIN -# ============================================================================= - -def main(): - dest_prefix = normalize_prefix(DESTINATION_DIR) - backups_prefix = normalize_prefix(BACKUPS_DIR) if BACKUPS_DIR else '' - client = create_validated_client() - if MINIO_DEBUG: - print("[DEBUG] Starting ensure_bucket phase...") - ensure_bucket(client) - - if CREATE_BACKUP: - ts = datetime.datetime.now().strftime('%Y%m%d_%H%M%S') - backup_folder = f"backup_{ts}" - print(f"Creating backup under '{backups_prefix}/{backup_folder}' from prefix '{dest_prefix}'") - backup_existing_files(client, dest_prefix, backups_prefix, backup_folder) - - # Firmware - if UPLOAD_FIRMWARE: - firmware_key = join_key(dest_prefix, 'firmware.bin') if dest_prefix else 'firmware.bin' - upload_file(client, LOCAL_FIRMWARE_PATH, firmware_key) - - # Manifest - if UPLOAD_MANIFEST: - manifest_key = join_key(dest_prefix, 'update.json') if dest_prefix else 'update.json' - upload_file(client, LOCAL_MANIFEST_PATH, manifest_key) - - # Data directory - if UPLOAD_DATA: - data_prefix = join_key(dest_prefix, 'data') if dest_prefix else 'data' - upload_directory(client, LOCAL_DATA_DIRECTORY, data_prefix) - - print("All uploads complete.") - -if __name__ == '__main__': - main() diff --git a/temporary/Temp/appcontrol old.html b/temporary/Temp/appcontrol old.html deleted file mode 100644 index 3033a2a..0000000 --- a/temporary/Temp/appcontrol old.html +++ /dev/null @@ -1,623 +0,0 @@ -{{NAVBAR}} - - - - App Control Configuration - - - - - - -

App Control Configuration

- - -
- Saved Animation Profiles - - - - -
- - -    - - -     - -
-
- - -
- - -
- Countdown Animation ( White Fill ) - - - - - - - - - - - - - -
-
- -
-
- -
- -
-
-
-
- -
-
- -
-
- -
- -
- Event 1 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event 2 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event 3 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event 4 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event 5 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event 6 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event 7 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event 8 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- - - - diff --git a/temporary/Temp/ata-boothifier-upgrade(copy).html b/temporary/Temp/ata-boothifier-upgrade(copy).html deleted file mode 100644 index e69de29..0000000 diff --git a/temporary/Temp/ata-boothifier-upgrade.html b/temporary/Temp/ata-boothifier-upgrade.html deleted file mode 100644 index 3327522..0000000 --- a/temporary/Temp/ata-boothifier-upgrade.html +++ /dev/null @@ -1,508 +0,0 @@ - - - - - - ATA Firmware Update - - - - -

ATA Firmware Update

- - -
- - -
- -
- - -
- -
- - -
- -
- -
-
- -
- - -
- - -
- - - - -
- - -
- - -
- - -
- - -
-
- - -
- -
- - - - diff --git a/temporary/Temp/ata-boothifier-upgradeV2.html b/temporary/Temp/ata-boothifier-upgradeV2.html deleted file mode 100644 index d95fd0b..0000000 --- a/temporary/Temp/ata-boothifier-upgradeV2.html +++ /dev/null @@ -1,547 +0,0 @@ - - - - - - ATA Firmware Update - - - - -

ATA Firmware Update

- - -
- - -
- -
- - -
- -
- - -
- -
- -
-
- -
- -
- -
- -
- -
- - -
- - -
- - - - -
- - -
- - -
- - -
- - -
-
- - -
- -
- - - - diff --git a/temporary/Temp/bleconfig.html b/temporary/Temp/bleconfig.html deleted file mode 100644 index fac456f..0000000 --- a/temporary/Temp/bleconfig.html +++ /dev/null @@ -1,16 +0,0 @@ -{{NAVBAR}} - - - - BLE Config - - - - - - -

App Control - Bluetooth Configuration

- - \ No newline at end of file diff --git a/temporary/Temp/colorPicket.html b/temporary/Temp/colorPicket.html deleted file mode 100644 index fe07814..0000000 --- a/temporary/Temp/colorPicket.html +++ /dev/null @@ -1,31 +0,0 @@ - - - -Color Picker - - - -
-

Countdown Animation

-
- - - - -
-

Selection Screen

-
- -
- - - diff --git a/temporary/Temp/command_processor.cpp b/temporary/Temp/command_processor.cpp deleted file mode 100644 index 8f4747c..0000000 --- a/temporary/Temp/command_processor.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "command_processor.h" - -int boothState[16]; - -void process_command(int* data, int paramCount) -{ - bool reply = false; - - switch(*data){ - case COMM_NULL: - break; - case COMM_REBOOT: - break; - case COMM_DIN: - break; - case COMM_DOUT: - break; - case COMM_RELAY: - break; - case COMM_AOUT: - break; - case COMM_AIN: - break; - case COMM_ECHO: - break; - case COMM_LED_STATUS: - break; - case COMM_GET_TEMP: - break; - case COMM_PLAY: - break; - case COMM_RF: - break; - case COMM_NEST: - break; - case COMM_BOOTH_STATE: - break; - case COMM_STRIP1: - - break; - case COMM_STRIP2: - break; - case COMM_OLED: - break; - default:; - } - - - if(reply){ - - } -} - -/* -int AppStates[16]; - -int getEvent(int index, int& ev){ - return ev[index]; - -} -enum BoothStates = { } -void RunAnimation(int stateIndex){ - switch (AppStates[stateIndex]){ - case 0: - break; - case 1: - break; - - } -} -*/ diff --git a/temporary/Temp/command_processor.h b/temporary/Temp/command_processor.h deleted file mode 100644 index 2367231..0000000 --- a/temporary/Temp/command_processor.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _COMMAND_PROCESSOR_H -#define _COMMAND_PROCESSOR_H - -extern int boothState[16]; - -void process_command(int* data, int paramCount); - -enum COMM_FUNC{ - COMM_NULL = 0, - COMM_REBOOT = 1, - COMM_DIN = 2, - COMM_DOUT = 3, - COMM_RELAY = 4, - COMM_AOUT = 5, - COMM_AIN = 6, - COMM_ECHO = 7, - COMM_LED_STATUS = 8, - COMM_GET_TEMP = 9, - COMM_PLAY = 10, - COMM_RF = 11, - - COMM_NEST = 30, - COMM_BOOTH_STATE = 50, - COMM_STRIP1 = 75, - COMM_STRIP2 = 100, - COMM_OLED = 125 -}; - - - -#endif diff --git a/temporary/Temp/eventTest.htm b/temporary/Temp/eventTest.htm deleted file mode 100644 index b30e777..0000000 --- a/temporary/Temp/eventTest.htm +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - -Event Container - - - -
-
- Event0
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- Mix  - Fwd -
-
- -
-
- -
-
- - diff --git a/temporary/Temp/firmware_html.h b/temporary/Temp/firmware_html.h deleted file mode 100644 index 7a7440f..0000000 --- a/temporary/Temp/firmware_html.h +++ /dev/null @@ -1,215 +0,0 @@ -#ifndef _FIRMWARE_HTML_H -#define _FIRMWARE_HTML_H - -#include - -const char firmware_html_page[] PROGMEM = R"rawliteral( - - - - Firmware Update - - - - - -

Firmware Update

-
-
- Local Update -
-
- -
-
- -
-
- -
- - - -
- -
- -
-
-
- - - - -)rawliteral"; - - -#endif \ No newline at end of file diff --git a/temporary/Temp/githubCert.h b/temporary/Temp/githubCert.h deleted file mode 100644 index 40a476e..0000000 --- a/temporary/Temp/githubCert.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef CERT_H - -#define CERT_H - -const char * github_rootCACertificate = \ - "-----BEGIN CERTIFICATE-----\n" -"MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs\n" -"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" -"d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\n" -"ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL\n" -"MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\n" -"LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug\n" -"RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm\n" -"+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW\n" -"PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM\n" -"xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB\n" -"Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3\n" -"hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg\n" -"EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF\n" -"MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA\n" -"FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec\n" -"nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z\n" -"eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF\n" -"hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2\n" -"Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\n" -"vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep\n" -"+OkuE6N36B9K\n" -"-----END CERTIFICATE-----\n"; - -#endif diff --git a/temporary/Temp/gridstyles.css b/temporary/Temp/gridstyles.css deleted file mode 100644 index bf326f6..0000000 --- a/temporary/Temp/gridstyles.css +++ /dev/null @@ -1,6 +0,0 @@ -.container{ - color:blue; - display: grid; - gap: 1rem; - grid-template-columns: 50% 1fr 1fr; -} \ No newline at end of file diff --git a/temporary/Temp/gridtest.html b/temporary/Temp/gridtest.html deleted file mode 100644 index 872e384..0000000 --- a/temporary/Temp/gridtest.html +++ /dev/null @@ -1,12 +0,0 @@ - - - CSS Grid - - -
-
Test text 1
-
Test text 1
-
Test text 1
-
Test text 1
-
- \ No newline at end of file diff --git a/temporary/Temp/hue-select-min.js b/temporary/Temp/hue-select-min.js deleted file mode 100644 index e25f5aa..0000000 --- a/temporary/Temp/hue-select-min.js +++ /dev/null @@ -1 +0,0 @@ -class HueSelect extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML='\n\t\t\n\t\t\n\t ',this.currentHue=0,this.colorList,this.hueLabel=this.shadowRoot.getElementById("hue-label");this.shadowRoot.getElementById("selectedColor").querySelector(".color-patch").addEventListener("mouseenter",(()=>{this.shadowRoot.querySelector(".dropdown-content").style.display="block"})),window.addEventListener("click",(t=>{const e=this.shadowRoot.querySelector(".dropdown-content");t.target.closest(".dropdown")||(e.style.display="none")})),this.createColorOptions(),this.setHue(0)}generateColors(){const t=[];for(let e=0;e<=360;e+=10)360==e&&(e=359),t.push(e);return t.push(-1),t.push(-2),t}createColorOption(t){const e=document.createElement("div");e.classList.add("color-option");const o=document.createElement("span");o.classList.add("color-patch");const n=document.createElement("span");n.classList.add("color-text"),n.textContent=t;const s=document.createElement("span");if(s.classList.add("rgb-hex"),-2===t)o.style.backgroundColor="rgb(0,0,0)",s.innerHTML="  #000000";else if(-1===t)o.style.backgroundColor="rgb(255,255,255)",s.innerHTML="  #FFFFFF";else{o.style.backgroundColor=`hsl(${t}, 100%, 50%)`;const e=this.hslToRgb(t,100,50).toUpperCase();s.innerHTML=`  ${e}`}return e.appendChild(o),e.appendChild(n),e.appendChild(s),e.addEventListener("click",(()=>this.handleColorSelection(t))),e}createColorOptions(){const t=this.shadowRoot.querySelector(".dropdown-content");this.colorList=this.generateColors(),this.colorList.forEach((e=>{const o=this.createColorOption(e);t.appendChild(o)}))}hslToRgb(t,e,o){let n,s,l;if(t/=360,o/=100,0===(e/=100))n=s=l=o;else{const r=(t,e,o)=>(o<0&&(o+=1),o>1&&(o-=1),o<1/6?t+6*(e-t)*o:o<.5?e:o<2/3?t+(e-t)*(2/3-o)*6:t),i=o<.5?o*(1+e):o+e-o*e,d=2*o-i;n=r(d,i,t+1/3),s=r(d,i,t),l=r(d,i,t-1/3)}const r=t=>{const e=Math.round(255*t).toString(16);return 1===e.length?"0"+e:e};return`#${r(n)}${r(s)}${r(l)}`}handleColorSelection(t){this.currentHue=t;const e=this.shadowRoot.getElementById("selectedColor").querySelector(".color-patch"),o=this.getRGBfromHue(t);e.style.backgroundColor=o,console.log(e.style.backgroundColor),this.setHueLabel(t),this.hideDropdown(),this.dispatchEvent(new CustomEvent("change",{detail:{hue:t,rgb:o}}))}getSelectedHue(){return this.currentHue}getSelectedRGB(){const t=this.shadowRoot.getElementById("selectedColor").textContent.trim();return parseFloat(t)}getRGBfromHue(t){return-1==t?"#FFFFFF":-2==t?"#000000":this.hslToRgb(t,100,50)}getSelectedRgb(){const t=this.getSelectedHue();return getRGBfromHue(t)}setHue(t){let e=t;-1===t||-2===t?e=t:(e=10*Math.round(t/10),e>=360&&(e=359),e<0&&(e=0)),this.currentHue=e,this.colorList.forEach((t=>{t===e&&this.handleColorSelection(e)})),this.hideDropdown()}hideDropdown(){this.shadowRoot.querySelector(".dropdown-content").style.display="none"}setHueLabel(t){this.hueLabel.textContent="Hue: "+t}}customElements.define("hue-select",HueSelect); \ No newline at end of file diff --git a/temporary/Temp/led_animation.cpp b/temporary/Temp/led_animation.cpp deleted file mode 100644 index 6b191af..0000000 --- a/temporary/Temp/led_animation.cpp +++ /dev/null @@ -1,1023 +0,0 @@ -#include "led_animation.h" - -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "common/HSVTable.h" -#include "common/neo_colors.h" -#include "common/color_tools.h" - -static const char* tag = "led_anim"; - - -int AnimTestModeCount = 0; - -ANIM_STATUS animStatus; -WHITE_FILL_STATUS whiteStatus; -HUE_PALLET_DISPENSER HuePalletDispenser;// (1, 1, 1); - -/********************************************************************/ - -// Animation Loop Template -EXIT_TYPE Animation_Loop(ANIM_STATUS &stateMon, int msFreq, TickType_t duration, std::function callback){ - stateMon.busy = true; - ulTaskNotifyTake( pdTRUE, 0); - EXIT_TYPE ret = EXIT_NORMAL; - - TickType_t startTicks = xTaskGetTickCount(); - - for(;;){ - TickType_t xLastWakeTime = xTaskGetTickCount(); - if(callback() == EXIT_FINISHED){ return EXIT_FINISHED; } - - if(ulTaskNotifyTake( pdTRUE, msFreq - ( xTaskGetTickCount() - xLastWakeTime ))){ // delay - stateMon.busy = false; - return EXIT_FROM_NOTIFY; - } - - // May have a duration limit - if(duration){ - if((xLastWakeTime - startTicks) > duration){ - return EXIT_TIMEOUT; - } - } - } - - return ret; -} - -int Const_White_Fill(WHITE_FILL_STATUS &status, FRONT_LIGHT light , float delayFactor, int countDown, int msFreq) { //int msRampUpTime, int msRampDownTime, int msHoldTime, int msFreq, float minDuty, float maxDuty){ - status.busy = true; - ulTaskNotifyTake( pdTRUE, 0); - - // Linear brightness rise - if(light.maxDuty > 100) { light.maxDuty = 100; } - if(light.maxDuty < 1){ light.maxDuty = 1; } - - if (light.minDuty >= light.maxDuty) { light.minDuty = light.maxDuty -1; } - if (light.minDuty < 0) { light.minDuty = 0; } - - // Pre Delay - if(delayFactor > 0.0){ - int waitDelay = int((float)countDown * delayFactor); - ESP_LOGD(tag, "Const Light Delay: %d, countDown: %d", waitDelay, countDown); - if(ulTaskNotifyTake( pdTRUE, waitDelay)){ // delay - status.busy = false; - return EXIT_FROM_NOTIFY; - } - } - - int rampSteps = (countDown - ((float)countDown * delayFactor)) / msFreq; - float dutyStep = ( light.maxDuty - pwmOut[animProps.frontLight.relayIndex]->currDuty ) / rampSteps; - if(dutyStep < 0.1) { dutyStep = 0.1; } - - //Log.noticeln(" upTime: %d, hold: %d, downTime: %d, msFreq: %d, minDuty: %F, maxDuty: %F", msRampUpTime, msHoldTime, msRampDownTime, msFreq, minDuty, maxDuty); - //Log.noticeln(" dutyStep: %F", dutyStep); - // Ramp Up - for(;;){ - //calc new newDuty value - float newDuty = pwmOut[animProps.frontLight.relayIndex]->currDuty + dutyStep; - - //check if dslrbooth jumped ahead and catch up - if(delayFactor > 0){ - if(status.dslrCountStatus > newDuty && ((status.dslrCountStatus-10) < 90)){ - newDuty = status.dslrCountStatus; - } - } - - // Set the new Duty - if(newDuty > light.maxDuty){ newDuty = light.maxDuty; } - pwmOut[animProps.frontLight.relayIndex]->setOutput(newDuty); // set duty - - if(newDuty >= light.maxDuty) { break;} // break if complete - - //check if there was a trigger to leave function - if(ulTaskNotifyTake( pdTRUE, msFreq )){ goto done; } // delay - } - - // Hold Steady for msHoldTime - //Serial.printf("Holding at %.1f\n\r", pwmOut[animProps.frontLight.relay]->currDuty ); - pwmOut[animProps.frontLight.relayIndex]->setOutput(light.maxDuty); - if(ulTaskNotifyTake( pdTRUE, light.holdTime )){ goto done; } // delay - - // Linear Ramp Down to Min - rampSteps = light.rampTime / msFreq; - dutyStep = abs(( pwmOut[animProps.frontLight.relayIndex]->currDuty - light.minDuty) / rampSteps ); - if(dutyStep < .1) { dutyStep = .1; } - //Serial.printf("stepDown: %.1f\n\r", dutyStep); - - for(;;){ - pwmOut[animProps.frontLight.relayIndex]->setOutput( pwmOut[animProps.frontLight.relayIndex]->currDuty - dutyStep ); // set duty - if( pwmOut[animProps.frontLight.relayIndex]->currDuty <= light.minDuty ) { break; } // break if complete - - //if(status.repeat){ goto done;} - if(ulTaskNotifyTake( pdTRUE, msFreq )){ break; } // delay - } - - done: - pwmOut[animProps.frontLight.relayIndex]->setOutput(light.minDuty); - status.busy = false; - status.dslrCountStatus = 0; - return 0; -} - - -// TODO Roamer/Helio type White Fill -//int Const_White_Fill_Disc -/****************************************************************/ -int Animation_White_Fill(LEDSTRIP& strip, ANIM_STATUS &stateMon, int msFillTime, rgbpixel_t& col, rgbpixel_t& baseCol) -{ - stateMon.busy = true; - ulTaskNotifyTake( pdTRUE, 0); - - int msDelay = msFillTime / strip.effSize; - - // Fill background first - for(int i = 0; i < strip.effSize; i++){ - strip.pixels[i] = baseCol; // skips index calc - } - - // Linear fill - for(int i = 0; i < strip.effSize; i++){ - TickType_t xLastWakeTime = xTaskGetTickCount(); - strip.setPixel(i, col, 255); - strip.show(true); - if(ulTaskNotifyTake( pdTRUE, msDelay - (xTaskGetTickCount() - xLastWakeTime ) == pdTRUE )){ return 1; } // delay - } - - stateMon.busy = false; - return 0; -} - -/******************************** WHITE FILL MIRRORED *********************************/ -EXIT_TYPE Animation_White_Fill_Mirrored(LEDSTRIP& strip, ANIMATION_EVENT& event) -{ - int msFillTime = 0; - if(event.countDown > 0){ // use countdown if available - msFillTime = event.countDown; - }else{ - msFillTime = map(event.param1, 0, 100, 0, 10000); - if(msFillTime < 1000){ msFillTime = 1000; } - } - - strip.powerDiv = (event.check4) ? 1 : 0; - - // TODO set msFreq from density - int msFreq = 25; - int halfSize = (strip.effSize / 2); - float steps = ((float)msFreq * (float)halfSize) / msFillTime; - strip.fill(col_black, 0, strip.effSize); // clear/off all pixels - - float stepsTotal = steps; - //int startIndex = 0; - int endIndex = stepsTotal; - //uint8_t frac = 0; - ESP_LOGD(tag, "whitefill-> msFillTime: %d, halfsize: %d, steps: %.3f, freq: %d, hue: %d", msFillTime, halfSize, steps, msFreq, event.hue); - - rgbpixel_t mainCol = GetColorFromHue(event.hue); - //rgbpixel_t fracCol; // = event.col1; - - int lastEndIndex = 0; - EXIT_TYPE ret = Animation_Loop( animStatus, msFreq, INFINITE_LOOP, [&](){ - - stepsTotal += steps; - endIndex = (int)stepsTotal; - if(endIndex != lastEndIndex){ - for(int i = lastEndIndex; i < endIndex; i++){ - strip.setPixelMirrored(i, mainCol); - } - lastEndIndex = endIndex; - strip.show(true); - } - - if(endIndex > (halfSize -1)){ return EXIT_FINISHED; } - - /* - frac = (stepsTotal - (int)stepsTotal) * 255; - fracCol = mainCol; - scalePixel(fracCol, frac); - linearizePixel(fracCol); - strip.setPixelMirrored(endIndex + 1, fracCol); - */ - //strip.show(true); - - return EXIT_NORMAL; - }); - - // TODO remove this trace later - //Log.traceln("exited white fill"); - return ret; -} - -float calculateSteps(int msFreq, float LEDCount, int msFillTime) { - return (msFreq * LEDCount) / msFillTime; -} - -void GetOptimizedStepInterval(float &steps, int &interval, int LEDCount, int msFillTime, int startInterval, float tolerance) -{ - steps = calculateSteps(startInterval, LEDCount, msFillTime); - - while (std::abs(steps - std::round(steps)) > tolerance) { - steps = calculateSteps(++startInterval, LEDCount, msFillTime); - } - interval = startInterval; - steps = round(steps); -} - - -EXIT_TYPE Animation_Linear_Brighten(LEDSTRIP& strip, ANIMATION_EVENT& event){ - return EXIT_NORMAL; -} - - -EXIT_TYPE Animation_Tick_Fill(LEDSTRIP& strip, ANIMATION_EVENT& event){ - return EXIT_NORMAL; -} - - - -/******************************** COLORED SNAKES *********************************/ -EXIT_TYPE Animation_Snakes(LEDSTRIP& strip, ANIMATION_EVENT& event, DIR_TYPE dirType, int cycles) -{ - bool mix = event.check1; - bool rotate = event.check2; - int sectors = constrain(event.param1/10, 1, 10); - int colorCount = constrain(event.param2/10, 1, 10); - strip.powerDiv = (event.check4) ? 1 : 0; - int msFreq = CalcEventInterval(event.speed, MIN_LED_UPDATE_INTERVAL, 100); - int snakeSize = trunc(roundf(strip.effSize / (float)sectors)); - - HuePalletDispenser.Initialize(event.hue, event.hueRange, colorCount); - ESP_LOGD(tag, " size: %d, sectors: %d, freq: %d", snakeSize, sectors, msFreq); - - // Create Color Pallet Array - rgbpixel_t col[colorCount]; - if(colorCount == 1){ - col[0] = GetColorFromHue(event.hue); - }else{ - for(int i = 0; i < colorCount; i++){ - float hue = HuePalletDispenser.GetNextPalletHue(); - col[i] = HUEtoRGB( hue ); - //ESP_LOGD(tag, " hue%d: ", hue); - } - } - - - LED_DIR dir = (dirType == DT_FWD)? DIR_FWD : DIR_REV; - int dirVal = (dir==DIR_FWD)? 1 : -1; - int pixIndex = 0, rotateOffset = 0, colIndex = 0; - bool colorCycle = true; - - strip.fill({0,0,0}, 0, strip.effSize); - - EXIT_TYPE ret = Animation_Loop( animStatus, msFreq, INFINITE_LOOP, std::function([&]() -> int { - - if(colorCycle){ - for(int sector = 0; sector < sectors; sector++){ - int pix = (sector * snakeSize) + pixIndex + rotateOffset; - if(mix){ - strip.setPixel(pix * dirVal, (rgbpixel_t)col[(colIndex + sector)%colorCount]); - }else{ - strip.setPixel(pix * dirVal, (rgbpixel_t)col[colIndex]); - } - } - }else{ - for(int sector = 0; sector < sectors; sector++){ - int pix = (sector * snakeSize) + pixIndex + rotateOffset; - strip.setPixel(pix * dirVal, {0,0,0}); - } - } - - if(rotate){ // turn off front pixels - strip.rotatePixels(dir); - rotateOffset = ++rotateOffset % strip.effSize; - } - strip.show(true); - - pixIndex = ++pixIndex % snakeSize; - - if(pixIndex == 0){ - if(colorCycle){ - colorCycle = false; - }else{ - // Check if there's an iteration limit - if(cycles){ - if(--cycles <= 0){ return EXIT_FINISHED; } - } - // Once full cycle here - if(dirType == DT_BOTH){ - dir = (dir == DIR_FWD)? DIR_REV : DIR_FWD; - dirVal = -dirVal; - } - colorCycle = true; - colIndex = ++colIndex % colorCount; // next color - } - } - return EXIT_NORMAL; - })); - - return ret; -} - - -/******************************** COLORED COMETS *********************************/ -#define COMET_SIZE_FACTOR 0.15 -#define COMET_FADE_FACTOR1 128 -#define COMET_FADE_FACTOR2 192 - -EXIT_TYPE Animation_Comets(LEDSTRIP& strip, ANIMATION_EVENT& event, DIR_TYPE dirType, int cycles){ - int sectorCount = constrain(event.param1/10, 1, 10); // cometCount also - int colorCount = constrain(event.param2/10, 1, 10); // color divisions - bool mix = event.check1; - bool rotate = true; - bool randomDecay = event.check2; - bool shorterTail = event.check3; - uint8_t fadeFactor = COMET_FADE_FACTOR1; - if(shorterTail){ fadeFactor = COMET_FADE_FACTOR2; } - strip.powerDiv = (event.check4) ? 1 : 0; - int msFreq = CalcEventInterval(event.speed, MIN_LED_UPDATE_INTERVAL, 100); - int sectorSize = trunc(roundf(strip.effSize / (float)sectorCount)); - - int cometSize = (strip.effSize / sectorCount) * COMET_SIZE_FACTOR; - if(cometSize < 1){ cometSize = 1;} - - HuePalletDispenser.Initialize(event.hue, event.hueRange, colorCount); - ESP_LOGD(tag, " size: %d, sectorCount: %d, freq: %d", sectorSize, sectorCount, msFreq); - - // Create Color Pallet Array - rgbpixel_t col[colorCount]; - if(colorCount == 1){ - col[0] = GetColorFromHue(event.hue); - }else{ - for(int i = 0; i < colorCount; i++){ - float hue = HuePalletDispenser.GetNextPalletHue(); - col[i] = HUEtoRGB( hue ); - //ESP_LOGD(tag, " hue%d: ", hue); - } - } - - LED_DIR dir; - if(dirType == DT_BOTH){ - dir = DIR_FWD; - }else{ - dir = (dirType == DT_FWD)? DIR_FWD : DIR_REV; - } - - strip.fill({0,0,0}, 0, strip.effSize); - - int rotateIndex = 0; - int cycleCount = 0; - int colIndex = 0; - int rotOffset = 0; - EXIT_TYPE ret = Animation_Loop( animStatus, msFreq, INFINITE_LOOP, std::function([&]() -> int { - - // Random Tail Decay here.... - if(randomDecay){ - for (int j = 0; j < strip.effSize; j++){ - if (random(10) > 5){ - fadeToBlackBy(strip.pixels[j], fadeFactor); - } - } - }else{ // Regular Tail Decay - for (int j = 0; j < strip.effSize; j++){ - fadeToBlackBy(strip.pixels[j], fadeFactor); - } - } - - // Draw Comets - if(mix){ - for(int sector = 0; sector < sectorCount; sector++){ - strip.fill((rgbpixel_t)col[(colIndex + sector) % colorCount], rotOffset + (sector * sectorSize), cometSize); - } - }else{ - for(int sector = 0; sector < sectorCount; sector++){ - strip.fill((rgbpixel_t)col[colIndex], rotOffset + (sector * sectorSize), cometSize); - } - } - - rotateIndex = ++rotateIndex % strip.effSize; - - if(dir == DIR_FWD){ rotOffset++; } - else{ rotOffset--; } - - // full rotation - if(rotateIndex == 0){ - // reverse rotation - if(dirType == DT_BOTH){ - dir = (dir == DIR_FWD)? DIR_REV : DIR_FWD; - } - - if(cycles){ - cycleCount++; - if(cycleCount >= cycles){ - return EXIT_FINISHED; - } - } - - colIndex = ++colIndex % colorCount; // Increment color index - } - strip.show(true); - - return EXIT_NORMAL; - })); - - return ret; -} - -void fadeToBlackBy(rgbpixel_t& pixel, uint8_t fadeAmount) { - pixel.red = (pixel.red <= 8) ? 0 : pixel.red - ((pixel.red * fadeAmount) >> 8); - pixel.grn = (pixel.grn <= 8) ? 0 : pixel.grn - ((pixel.grn * fadeAmount) >> 8); - pixel.blu = (pixel.blu <= 8) ? 0 : pixel.blu - ((pixel.blu * fadeAmount) >> 8); -} - -inline uint8_t nscale8(uint8_t i, uint8_t scale) { - return (((int)i * (int)(scale)) >> 8) + ((i && scale) ? 1 : 0); -} - - -/******************************** COLORED SECTORS *********************************/ -EXIT_TYPE Animation_Sectors(LEDSTRIP& strip, ANIMATION_EVENT& event, DIR_TYPE dirType, int cycles){ - bool rotate = event.check2; - int sectorCount = constrain(event.param1/10, 2, 10); - int colorCount = constrain(event.param2/10, 1, 10); - - strip.powerDiv = (event.check4) ? 1 : 0; - int msFreq = CalcEventInterval(event.speed, MIN_LED_UPDATE_INTERVAL, 100); - int sectorSize = trunc(roundf(strip.effSize / (float)sectorCount)); - - ESP_LOGD(tag, "hue: %d, range: %d\n", event.hue, event.hueRange); - HuePalletDispenser.Initialize(event.hue, event.hueRange, colorCount); - ESP_LOGD(tag, "size: %d, sectorCount: %d, colors: %d, freq: %d", sectorSize, sectorCount, colorCount, msFreq); - - // Create Color Pallet Array - rgbpixel_t col[colorCount]; - if(colorCount == 1){ - col[0] = GetColorFromHue(event.hue); - }else{ - for(int i = 0; i < colorCount; i++){ - float hue = HuePalletDispenser.GetNextPalletHue(); - col[i] = HUEtoRGB( hue ); - //ESP_LOGD(tag, "hue%d: ", hue); - } - } - - LED_DIR dir; - if(dirType == DT_BOTH){ - dir = DIR_FWD; - }else{ - dir = (dirType == DT_FWD)? DIR_FWD : DIR_REV; - } - - strip.fill({0,0,0}, 0, strip.effSize); - - bool updateColors = true; - int rotateIndex = 0; - int cycleCount = 0; - int colIndex = 0; - - EXIT_TYPE ret = Animation_Loop( animStatus, msFreq, INFINITE_LOOP, std::function([&]() -> int { - - if(updateColors){ // - for(int sector = 0; sector < sectorCount; sector++){ - strip.fill((rgbpixel_t)col[(colIndex + sector) % colorCount], sector * sectorSize, sectorSize); - } - colIndex = ++colIndex % colorCount; // Increment color index - updateColors = false; - } - - if(rotate){ // turn off front pixels - strip.rotatePixels(dir); - rotateIndex = ++rotateIndex % strip.effSize; - - // full rotation - if(rotateIndex == 0){ - // reverse rotation - if(dirType == DT_BOTH){ - dir = (dir == DIR_FWD)? DIR_REV : DIR_FWD; - } - - if(cycles){ - cycleCount++; - if(cycleCount >= cycles){ - return EXIT_FINISHED; - } - } - - updateColors = true; - } - } - - strip.show(true); - return EXIT_NORMAL; - })); - - return ret; -} - - -/******************************** DASHES SECTORS *********************************/ -EXIT_TYPE Animation_Dashes(LEDSTRIP& strip, ANIMATION_EVENT& event, DIR_TYPE dirType, int cycles){ - int sectorCount = constrain(event.param1/10, 1, 10); - int colorCount = constrain(event.param2/10, 1, 10); - bool mix = event.check1; - bool rotate = event.check2; - - strip.powerDiv = (event.check4) ? 1 : 0; - int msFreq = CalcEventInterval(event.speed, MIN_LED_UPDATE_INTERVAL, 100); - int sectorSize = trunc(roundf(strip.effSize / (float)sectorCount)); - - HuePalletDispenser.Initialize(event.hue, event.hueRange, colorCount); - ESP_LOGD(tag, " size: %d, sectorCount: %d, freq: %d", sectorSize, sectorCount, msFreq); - - // Create Color Pallet Array - rgbpixel_t col[colorCount]; - if(colorCount == 1){ - col[0] = GetColorFromHue(event.hue); - }else{ - for(int i = 0; i < colorCount; i++){ - float hue = HuePalletDispenser.GetNextPalletHue(); - col[i] = HUEtoRGB( hue ); - //ESP_LOGD(tag, " hue%d: ", hue); - } - } - - LED_DIR dir; - if(dirType == DT_BOTH){ - dir = DIR_FWD; - }else{ - dir = (dirType == DT_FWD)? DIR_FWD : DIR_REV; - } - - strip.fill({0,0,0}, 0, strip.effSize); - - bool updateColors = true; - int rotateIndex = 0; - int cycleCount = 0; - int colIndex = 0; - - EXIT_TYPE ret = Animation_Loop( animStatus, msFreq, INFINITE_LOOP, std::function([&]() -> int { - if(updateColors){ // - if(mix){ - for(int sector = 0; sector < sectorCount; sector++){ - strip.fill((rgbpixel_t)col[(colIndex + sector) % colorCount], sector * sectorSize, sectorSize/2); - } - }else{ - for(int sector = 0; sector < sectorCount; sector++){ - strip.fill((rgbpixel_t)col[colIndex], sector * sectorSize, sectorSize/2); - } - } - - colIndex = ++colIndex % colorCount; // Increment color index - updateColors = false; - } - - if(rotate){ // turn off front pixels - strip.rotatePixels(dir); - rotateIndex = ++rotateIndex % strip.effSize; - - // full rotation - if(rotateIndex == 0){ - // reverse rotation - if(dirType == DT_BOTH){ - dir = (dir == DIR_FWD)? DIR_REV : DIR_FWD; - } - - if(cycles){ - cycleCount++; - if(cycleCount >= cycles){ - return EXIT_FINISHED; - } - } - - updateColors = true; - } - } - - strip.show(true); - - return EXIT_NORMAL; - })); - - return ret; -} - - -/****************************************************************/ -void Animation_TransTo_Color(LEDSTRIP& strip, ANIM_STATUS &stateMon, int msTransTime, int msFreq, rgbpixel_t newCol) -{ - stateMon.busy = true; - ulTaskNotifyTake( pdTRUE, 0); - - int numSteps = (msTransTime / msFreq); - if (numSteps == 0) { return; } - - for (uint8_t step = 0; step < numSteps; step++) { - TickType_t xLastWakeTime = xTaskGetTickCount(); - - for (size_t i = 0; i < strip.effSize; i++) { - rgbpixel_t colorDiff = { - .red = static_cast((newCol.red - strip.pixels[i].red) / numSteps), - .grn = static_cast((newCol.grn - strip.pixels[i].grn) / numSteps), - .blu = static_cast((newCol.blu - strip.pixels[i].blu) / numSteps) - }; - strip.pixels[i].red += colorDiff.red; - strip.pixels[i].grn += colorDiff.grn; - strip.pixels[i].blu += colorDiff.blu; - } - - strip.show(true); - if(ulTaskNotifyTake( pdTRUE, msFreq - (xTaskGetTickCount() - xLastWakeTime ) == pdTRUE )){ return; } // delay - } - stateMon.busy = false; -} - - -/******************************** HUE SPECTRUM MIRRORED *********************************/ - -EXIT_TYPE Animation_Hue_Spectrum_Mirrored(LEDSTRIP& strip, ANIMATION_EVENT& event, TickType_t duration){ - int msFreq = CalcEventInterval(event.speed, MIN_LED_UPDATE_INTERVAL, 100); - strip.powerDiv = (event.check4) ? 1 : 0; - Fill_Hue_Spectrum_Mirrored(strip, event.hue, event.hueRange); - - EXIT_TYPE ret = Animation_Loop( animStatus, msFreq, duration, std::function([&]() -> int { - strip.show(true); - strip.rotatePixels(DIR_FWD); - return EXIT_NORMAL; - })); - - return ret; -} - -void Fill_Hue_Spectrum(LEDSTRIP& strip, float hue, float range) -{ - HuePalletDispenser.Initialize(hue, range, strip.effSize); - for(int i = 0; i < strip.effSize; i++){ - strip.setPixel(i, HUEtoRGB( HuePalletDispenser.GetNextPalletHue() )); - } -} - -void Fill_Hue_Spectrum_Mirrored(LEDSTRIP& strip, float hue1, float hue2) -{ - HuePalletDispenser.Initialize(hue1, hue2, strip.effSize / 2.0); - - for(int i = 0; i < strip.effSize/2; i++){ - strip.setPixelMirrored(i, HUEtoRGB( HuePalletDispenser.GetNextPalletHue() )); - } -} - - -/******************************** PULSE COLOR CYCLING *********************************/ -//TODO Add Linearizing for smoother transitions -#define PWR_STEP 8 -EXIT_TYPE Animation_Pulse_Color_Cycling(LEDSTRIP& strip, ANIMATION_EVENT& event){ - int colorSteps = event.param1/10.0; - if(colorSteps < 3){ colorSteps = 2; } - - strip.powerDiv = (event.check4) ? 1 : 0; - int msFreq = CalcEventInterval(event.speed, MIN_LED_UPDATE_INTERVAL, 100); - - HuePalletDispenser.Initialize(event.hue, event.hueRange, colorSteps); - - int pwrStep = PWR_STEP; - int pwr = pwrStep; - - rgbpixel_t col = HUEtoRGB(HuePalletDispenser.GetNextPalletHue()); - - EXIT_TYPE ret = Animation_Loop( animStatus, msFreq, INFINITE_LOOP, std::function([&]() -> int { - // ramp up/down brightness - rgbpixel_t col_pwr = col; - scalePixel(col_pwr, (uint8_t)pwr); - linearizePixel(col_pwr); - strip.fill(col_pwr, 0, strip.effSize); - strip.show(true); - - pwr += pwrStep; - if(pwr >= (256-PWR_STEP) || pwr <= PWR_STEP){ - pwrStep = -pwrStep; // switch brightness direction - - // Change color - if(pwrStep > 0){ - col = HUEtoRGB(HuePalletDispenser.GetNextPalletHue()); - } - } - - return EXIT_NORMAL; - })); - - return ret; -} - - -/******************************** RAINBOW *********************************/ -// TODO Need more Red for rainboow -EXIT_TYPE Animation_Rainbow(LEDSTRIP& strip, ANIMATION_EVENT& event, TickType_t duration){ - int msFreq = CalcEventInterval(event.speed, MIN_LED_UPDATE_INTERVAL, 100); - double hueStep = 359.2 / (strip.effSize-1); - - strip.powerDiv = (event.check4) ? 1 : 0; - - for(int i = 0; i < strip.effSize; i++){ - strip.setPixel(i, HUEtoRGB((int)round(i*hueStep))); - } - - EXIT_TYPE ret = Animation_Loop( animStatus, msFreq, duration, std::function([&]() -> int { - strip.rotatePixels(DIR_FWD); - strip.show(true); - return EXIT_NORMAL; - })); - - return ret; -} - - -/******************************** FIRE ANIMATION *********************************/ -//TODO Get these fire params from json -#define FIRE_SPARK_PIXEL_PERCENT 15 -#define MIN_FIRE_COOLING 20 -#define MAX_FIRE_COOLING 100 -#define MIN_FIRE_SPARKING 50 -#define MAX_FIRE_SPARKING 200 -uint8_t *heat; -uint8_t sparkCount; - -EXIT_TYPE Animation_Fire(LEDSTRIP& strip, ANIMATION_EVENT& event){ - int msFreq = CalcEventInterval(event.speed, MIN_LED_UPDATE_INTERVAL, 100); - bool cycleColors = event.check1; - uint8_t sparking = map(event.param1, 0, 100, MIN_FIRE_SPARKING, MAX_FIRE_SPARKING); // input, input max, output min, out max - uint8_t cooling = map(event.param2, 0, 100, MIN_FIRE_COOLING, MAX_FIRE_COOLING); - - strip.powerDiv = (event.check4) ? 1 : 0; - - int duration = map(event.hueRange, 0, 360, 0, 60000 ); // upto 1 minute - if(cycleColors && duration == 0) { duration = 10000; } - if(!cycleColors && duration > 0) { duration = 0; } - - FIRE_COLOR fireColor = RED_FIRE; - - // Choose which Color comes closest - if(event.hue = -1 || event.hue == -2) { event.hue == 0;} - rgbpixel_t col = HUEtoRGB(event.hue); - if (col.red >= col.grn && col.red >= col.blu) { - fireColor = RED_FIRE; - } else if (col.grn >= col.red && col.grn >= col.blu) { - fireColor = GREEN_FIRE; - } else { - fireColor = BLUE_FIRE; - } - - EXIT_TYPE ret; - while(1){ - ret = Animation_Loop( animStatus, msFreq, duration, std::function([&]() -> int { - Fire_Update( strip, fireColor, cooling, sparking); - strip.show(true); - return EXIT_NORMAL; - })); - - if(ret == EXIT_TIMEOUT){ - fireColor = (FIRE_COLOR)(((int)fireColor + 1) % 3); - continue; - } - break; - } - - return ret; -} - -void LEDStrip_FireInit(LEDSTRIP& strip){ - sparkCount = (strip.effSize/2 * FIRE_SPARK_PIXEL_PERCENT) / 100; - heat = new uint8_t[strip.effSize/2]; - for(int i = 0; i < (strip.effSize/2); i++){ - heat[i] = 0; - } - - srand(70); -} - -void Fire_Update( LEDSTRIP& strip, FIRE_COLOR fire, int Cooling, int Sparking) { - int cooldown; - - // Step 1. Cool down every cell a little - for( int i = 0; i < (strip.effSize/2); i++) { - cooldown = rand() % ((Cooling * 10) / (strip.effSize/2) + 2); - - if(cooldown > heat[i]) { - heat[i] = 0; - }else { - heat[i] -= cooldown; - } - } - - // Step 2. Heat from each cell drifts 'up' and diffuses a little - // Starts from farthest and work down to the source - for( int k = (strip.effSize/2) - 1; k >= 2; k--) { - heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3; - } - - // Step 3. Randomly ignite new 'sparks' near the bottom - if( (rand() % 255) < Sparking ) { - int y = (rand() % sparkCount); - heat[y] += 160 + (rand() % 95); - } - - // Step 4. Convert heat to LED colors - for( int j = 0; j < strip.effSize/2; j++) { - strip.setPixelMirrored(j, GetPixelHeatColor(fire, heat[j])); - } -} - -rgbpixel_t GetPixelHeatColor ( FIRE_COLOR fire, uint8_t temperature){ - rgbpixel_t led; - - // Scale 'heat' down from 0-255 to 0-191 - //uint8_t T = ((uint16_t)(temperature*191))>>8; - uint8_t T = (uint16_t)(temperature*120) >> 8; - - // calculate ramp up from (heat ramp) - int hr = T & 0x3F; // 0..63 - hr <<= 2; // scale up to 0..252 - - // Choose Fire Color - switch(fire){ - case RED_FIRE:{ - //if((hr + 32) & 255){ hr = 255; } - if((hr + 32) > 255){ hr = 255; } - // figure out which third of the spectrum we're in: - if( T > 117) { // hottest - led = (rgbpixel_t){ .red=120, .grn=120, .blu=(uint8_t)hr }; // spark color - } else if( T > 48 ) { // middle - led = (rgbpixel_t){ .red=255, .grn=(uint8_t)hr, .blu=0 }; // flame color - } else{ // coolest - led = (rgbpixel_t){ .red=(uint8_t)hr, .grn=0, .blu=0 }; // cooling color - } - break; - } - case BLUE_FIRE:{ - if( T > 117) { // hottest - led = (rgbpixel_t){ .red=120, .grn=(uint8_t)hr, .blu=120 }; - } else if( T > 48 ) { // middle - led = (rgbpixel_t){ .red=(uint8_t)hr, .grn=0, .blu=255 }; - } else { // coolest - led = (rgbpixel_t){ .red=0, .grn=0,.blu=(uint8_t)hr }; - } - break; - } - default:{ // GRN_FIRE - if( T > 117) { // hottest - led = (rgbpixel_t){ .red=(uint8_t)hr, .grn=120, .blu=120 }; - }else if ( T > 48 ) { // middle - led = (rgbpixel_t){ .red=0, .grn=255, .blu=(uint8_t)hr }; - }else { // coolest - led = (rgbpixel_t){ .red=0, .grn=(uint8_t)hr, .blu=0 }; - } - break; - } - } - - return led; -} - - - -/******************************** Serial Out Toggle *********************************/ -EXIT_TYPE Animation_Serial_Test2(LEDSTRIP& strip, int msFreq, const char* s1, const char* s2){ - //Animation_Loop( animStatus, msFreq, [&](){ - EXIT_TYPE ret = Animation_Loop( animStatus, msFreq, INFINITE_LOOP, std::function([&]() -> int { - static bool x = false; - - if(x){ - Serial.print("[ "); Serial.print( s1 ); Serial.print(" ]\r"); - }else{ - Serial.print("[ "); Serial.print( s2 ); Serial.print(" ]\r"); - } - x = !x; - - strip.show(true); - return EXIT_NORMAL; - })); - - return ret; -} - - -/******************************** *********************************/ - -void Animation_SparkleHue(LEDSTRIP& strip, ANIM_STATUS &stateMon, int msFreq, uint8_t hueRange, uint8_t hue, uint8_t sat, uint8_t val) -{ - stateMon.busy = true; - ulTaskNotifyTake( pdTRUE, 0); - - for(;;){ - TickType_t xLastWakeTime = xTaskGetTickCount(); - - //decay all leds - for(int i = 0; i < strip.effSize; i++){ - // strip.scale(strip.pixels[i], 0.5 * 0xFF); - } - - // Random Pixel - //int index = random(strip.effSize); - //uint16_t h = (random(hueRange * 2) - hueRange) % HUE_MAX; - //strip.setPixel(index, h, sat, val); - - strip.show(true); - if(ulTaskNotifyTake( pdTRUE, msFreq - (xTaskGetTickCount() - xLastWakeTime ) == pdTRUE )){ return; } // delay - } - - stateMon.busy = false; -} - -void Animation_SparkleColor(LEDSTRIP& strip, ANIM_STATUS &stateMon, int msFreq, rgbpixel_t col) -{ - stateMon.busy = true; - ulTaskNotifyTake( pdTRUE, 0); - - for(;;){ - TickType_t xLastWakeTime = xTaskGetTickCount(); - - //decay all leds - for(int i = 0; i < strip.effSize; i++){ - // strip.scale(strip.pixels[i], 0.5 * 0xFF); - } - - // Random Pixel - int index = random(strip.effSize); - strip.pixels[index] = col; - - strip.show(true); - if(ulTaskNotifyTake( pdTRUE, msFreq - (xTaskGetTickCount() - xLastWakeTime ) == pdTRUE )){ return; } // delay - } - - stateMon.busy = false; -} - - - -/******************************** test Functions *********************************/ -EXIT_TYPE Animation_SetPixel(LEDSTRIP& strip, ANIMATION_EVENT& event){ - return EXIT_NORMAL; -} - -EXIT_TYPE Animation_Clear(LEDSTRIP& strip, ANIMATION_EVENT& event){ - return EXIT_NORMAL; -} - - - - - - - - -/******************************** *********************************/ - -// This takes into account that the web color picker hue is reversed -float GetHueRangeWeb(float hue1, float hue2){ - float rng; - if (hue1 > hue2) { rng = hue1 - hue2; } - else { rng = 360.0 + hue1 - hue2; } - - if (rng < 0.0) { rng += 360.0; } - else if (rng > 360.0) { rng -= 360.0; } - - return rng; -} - -float GetHueRange(float hue1, float hue2){ - float range = hue2 - hue1; - if(hue2 < hue1){ range += 360.0; } - //Log.noticeln(" hue range: %d", hueRange); - return range; -} - - - -/******************************** SPEED CALC HELPER FUNCTIONS *********************************/ - -void Init_Speed_Range(float startSpeed, float endSpeed, int steps){ - -} - -float GetNextSpeed(void){ - return 0.0; -} - - - -int CalcEventInterval(float speed, int min, int max){ - int range = max - min; - return (max - ((speed/100.0) * range)); -} - -rgbpixel_t GetColorFromHue(int hue){ - if(hue == -1){ - return col_white; - }else if(hue == -2){ - return col_black; - }else if(hue >= 0 && hue <= 360){ - return HUEtoRGB(hue); - } - return col_black; -} - - - \ No newline at end of file diff --git a/temporary/Temp/led_animation.h b/temporary/Temp/led_animation.h deleted file mode 100644 index 21ed576..0000000 --- a/temporary/Temp/led_animation.h +++ /dev/null @@ -1,205 +0,0 @@ -#ifndef _LED_ANIMATION_H -#define _LED_ANIMATION_H - -#include "common/LEDStrip.h" -#include "led_strip.h" -#include "my_board.h" -#include -#include "common/HSVTable.h" - -#define HUE_MAX 767 - -enum EXIT_TYPE { EXIT_NORMAL, EXIT_FROM_NOTIFY, EXIT_FINISHED, EXIT_TIMEOUT }; - - -#define HUE_CALC_METHOD 0 -// TODO Fix hue range... 0-359 or 0-360; -#if HUE_CALC_METHOD == 0 - #define HUEtoRGB(x) trueHSV(x) -#elif HUE_CALC_METHOD == 1 - #define HUEtoRGB(x) sineHSV(x) -#elif HUE_CALC_METHOD == 2 - #define HUEtoRGB(x) pwrHSV(x) -#endif - -#define RGBtoHUE(x) RGBToHSV(x) - -#define INFINITE_LOOP 0 - - -enum DIR_TYPE { DT_REV, DT_FWD, DT_BOTH }; - -typedef struct { - int RampUpTime; - int msRampDownTime; - int msHoldTime; - int msFreq; - float minDuty; - float maxDuty; - int interval; - uint8_t pwr; -}params_whiteFill; - -typedef struct { - int hue; - int cooling; - int sparking; - int interval; - uint8_t pwr; -}params_fire_hue; - -typedef struct { - rgbpixel_t col1; - rgbpixel_t col2; - uint8_t range; /* hue range 0-127*/ - int density; - uint8_t step; /* range step inteval*/ - int interval; - uint8_t pwr; -}params_rain; - -#define ANIMTESTMODE_TIMEOUT (20 * 1000) // 20 secs - -typedef struct { - int EventTestCountdown = 0; - int EventsIndex; // upto 8 events based on anim-events.json - int EventsCount; // upto 8 events based on anim-events.json - int PopupAnimIndex; - bool busy; - bool repeat; - int countStatus; -}ANIM_STATUS; - -typedef struct { - bool busy; - int dslrCountStatus; -}WHITE_FILL_STATUS; - -extern ANIM_STATUS animStatus; -extern WHITE_FILL_STATUS whiteStatus; - -float calculateSteps(int msFreq, float LEDCount, int msFillTime); -void GetOptimizedStepInterval(float &steps, int &interval, int LEDCount, int msFillTime, int startInterval, float tolerance); - -float GetNextPalletHue(void); -void Init_Hue_Range_Pallet(float hue1, float hue2, int colSteps); - -float GetHueRange(float hue1, float hue2); -float GetHueRangeWeb(float hue1, float hue2); - -int CalcEventInterval(float speed, int min, int max); - -/******************************** ANIMATION LOOP HELPER ********************************* - * All Animations should use this lopp helper. - * Logic for monitoring exit notifications - * Timeout in mSec can be set to exit -**************************************************************************************/ -EXIT_TYPE Animation_Loop(ANIM_STATUS &stateMon, int msFreq, TickType_t duration, std::function callback=NULL); - -// min:0-100, max:0-100 -//int Const_White_Fill(WHITE_FILL_STATUS &status, int msRampUpTime, int msHoldTime, int msRampDownTime, int msFreq, float minDuty, float maxDuty); -int Const_White_Fill(WHITE_FILL_STATUS &status, FRONT_LIGHT light , float delayFactor, int countDown, int msFreq); -//int Const_White_Fill_HelioType(ANIM_STATUS &stateMon, float startPoint, int msRampUpTime, int msRampDownTime, int msHoldTime, int msFreq, float minDuty, float maxDuty); - -EXIT_TYPE Animation_White_Fill_Mirrored(LEDSTRIP& strip, ANIMATION_EVENT& event); - -EXIT_TYPE Animation_Linear_Brighten(LEDSTRIP& strip, ANIMATION_EVENT& event); -EXIT_TYPE Animation_Tick_Fill(LEDSTRIP& strip, ANIMATION_EVENT& event); - - -/******************************** COLORED SNAKES ********************************* - * cycles=0=infinite - * (check1) "mix"=false, all appearing sectors will be the same color until the next iteration - * "mix"=true, each meteor color will be different - * (check2) "roate", add rotation to animation - * (hue range) hue range (0-360) - * (param1) sectors - * (param2) colorCount, number of color divisions -**************************************************************************************/ -EXIT_TYPE Animation_Snakes(LEDSTRIP& strip, ANIMATION_EVENT& event, DIR_TYPE dir=DT_BOTH, int cycles=0); -void drawSnakeMix(LEDSTRIP& strip, int sectors, float hue1, float hue2, int colorCount); - - -/******************************** COLORED COMETS ********************************* - *(check1) "mix"=false, all appearing comets will be the same color until the next iteration - * (check2) "mix"=true, each comets color will be different - * (param1) hue range (0-360) - * (param2) colorCount, number of color divisions -**************************************************************************************/ -EXIT_TYPE Animation_Comets(LEDSTRIP& strip, ANIMATION_EVENT& event, DIR_TYPE dir=DT_BOTH, int cycles=0); - -void fadeToBlackBy(rgbpixel_t& pixel, uint8_t fadeAmount); -inline uint8_t nscale8(uint8_t i, uint8_t scale); - -/******************************** COLORED SECTORS ********************************* - * (check1) "mix"=false, all appearing sectors will be the same color until the next iteration - * (check2) "mix"=true, each meteor color will be different - * (param1) hue range (0-360) - * (param2) colorCount, number of color divisions -**************************************************************************************/ -EXIT_TYPE Animation_Sectors(LEDSTRIP& strip, ANIMATION_EVENT& event, DIR_TYPE dir=DT_BOTH, int cycles=0); - - -/******************************** COLORED DASHES ********************************* - * (check1) "mix"=false, all appearing dashes will be the same color until the next iteration - * (check2) "mix"=true, each dash color will be different - * (param1) hue range (0-360) - * (param2) colorCount, number of color divisions -**************************************************************************************/ -EXIT_TYPE Animation_Dashes(LEDSTRIP& strip, ANIMATION_EVENT& event, DIR_TYPE dirType=DT_BOTH, int cycles=0); - - -/******************************** HUE SPECTRUM ********************************* - * (check1) "mix"=false, all appearing dashes will be the same color until the next iteration - * (check2) "mix"=true, each dash color will be different - * (param1) hue range (0-360) - * (param2) colorCount, number of color divisions -**************************************************************************************/ -EXIT_TYPE Animation_Hue_Spectrum(LEDSTRIP& strip, ANIMATION_EVENT& event, TickType_t duration); -EXIT_TYPE Animation_Hue_Spectrum_Mirrored(LEDSTRIP& strip, ANIMATION_EVENT& event, TickType_t duration); -void Fill_Hue_Spectrum(LEDSTRIP& strip, float hue1, float hue2); -void Fill_Hue_Spectrum_Mirrored(LEDSTRIP& strip, float hue1, float hue2); - - -/************************ RAINBOW *********************/ -EXIT_TYPE Animation_Rainbow(LEDSTRIP& strip, ANIMATION_EVENT& event, TickType_t duration); - -/************************ PULSE COLOR *********************/ -EXIT_TYPE Animation_Pulse_Color_Cycling(LEDSTRIP& strip, ANIMATION_EVENT& event); - - -/**************** FIRE ****************/ -enum FIRE_COLOR { RED_FIRE, GREEN_FIRE, BLUE_FIRE}; -//void Animation_Fire(LEDSTRIP& strip, ANIMATION_EVENT& event, FIRE_COLOR fire, TickType_t duration); -EXIT_TYPE Animation_Fire(LEDSTRIP& strip, ANIMATION_EVENT& event); -void LEDStrip_FireInit(LEDSTRIP& strip); -void Fire_Update( LEDSTRIP& strip, FIRE_COLOR fire, int Cooling, int Sparking); -rgbpixel_t GetPixelHeatColor ( FIRE_COLOR fire, uint8_t temperature); - - - - -/************************ *********************/ -void Animation_Splash(LEDSTRIP& strip); -void Animation_SparkleColor(LEDSTRIP& strip, int msFreq); -void Animation_SparkleHue(LEDSTRIP& strip, ANIMATION_EVENT& event); - -EXIT_TYPE Animation_Serial_Test2(LEDSTRIP& strip, int msFreq, const char* s1, const char* s2); -// msTransTime(Duration), msFreq(update interval) -void Animation_TransTo_Color(LEDSTRIP& strip, ANIM_STATUS &stateMon, int msTransTime, int msFreq, rgbpixel_t col); - - -void drawSectorsHueSingle(LEDSTRIP& strip, rgbpixel_t col, float hue1, float hue2, int sectors) ; -void drawSectorsHueMix(LEDSTRIP& strip, float hue1, float hue2, int sectors, int colorCount); - - - -/************************ TEST ANIMATIONS *********************/ -EXIT_TYPE Animation_SetPixel(LEDSTRIP& strip, ANIMATION_EVENT& event); -EXIT_TYPE Animation_Clear(LEDSTRIP& strip, ANIMATION_EVENT& event); - - -rgbpixel_t GetColorFromHue(int hue); - - -#endif \ No newline at end of file diff --git a/temporary/Temp/led_strip.cpp b/temporary/Temp/led_strip.cpp deleted file mode 100644 index 328c197..0000000 --- a/temporary/Temp/led_strip.cpp +++ /dev/null @@ -1,564 +0,0 @@ -#include "led_strip.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include - -#include -#include -#include "common/led_animation.h" -#include "common/LEDStrip.h" -#include "global.h" -#include "common/neo_colors.h" -#include "common/HSVTable.h" -#include "JsonConstrain.h" -#include "my_board.h" -#include "luma_master.h" -#include "common/luma-stiks.h" - -#define STRIP1_PIN RGBLED1_Pin -#define STRIP2_PIN RGBLED2_Pin - -#define POWERUP_TIME 3000 - -static const char* tag = "led_strip"; - -ANIMATION_PROPS animProps; - -LEDSTRIP *strip1; -LEDSTRIP *strip2; -TaskHandle_t Strip1_Task_Handle; -TaskHandle_t Strip2_Task_Handle; -TaskHandle_t FrontLight_Task_Handle; - -QueueHandle_t eventQueue = xQueueCreate( 4, sizeof( ANIMATION_EVENT ) ); -QueueHandle_t whiteQueue = xQueueCreate( 4, sizeof( ANIMATION_EVENT ) ); - -ANIMATION_EVENT lastNormalEventMsg; -ANIMATION_EVENT eventMsg; - -LUMA_PACKET TempLumaPacket; - -int CurrentRunningEventIndex = -1; - - -void Init_LED_Devices(BOARD_PINS boardPins) -{ - ESP_LOGD(tag, "Strips Initialization entered..."); - File file = LittleFS.open("/cfg/led-devices.json"); - - if(!file){ - ESP_LOGE(tag,"Error opening led-devices.json!"); - file.close(); - }else{ - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - if(error){ ESP_LOGE(tag, "led-devices.json deserialize error!.."); return;} - - // ********** STRIP1 ******************************** - JsonObject stripJson = doc["strip1"]; - if(jsonConstrainBool(tag, stripJson, "en", false)){ - int port = jsonConstrain(tag, stripJson, "i2s-ch", 0, 1, 0); - int size = jsonConstrain(tag, stripJson, "size", 1, 200, 10); - //int pin = jsonConstrainInt(stripJson, "pin", 0, 48, RGBLED1_Pin); - LED_ORDER order= getRGBOrder( jsonConstrainString(tag, stripJson, "rgb-order", "grb").c_str() ); - int shift = jsonConstrain(tag, stripJson, "shift", -size, size, 0); - int offset = jsonConstrain(tag, stripJson, "offset", -size, size, 0); - int core = jsonConstrain(tag, stripJson, "core", 0, 1, 0); - int powerDiv = jsonConstrain(tag, stripJson, "power-div", 0, 3, 0); - - strip1 = new LEDSTRIP(port, size, boardPins.rgb1, order, shift, offset); - strip1->setPowerDiv(powerDiv); - ESP_LOGI(tag,"Strip1 initialized."); - ESP_LOGD(tag," Size: %d, port: %d, shift: %d, offset: %d", size, port, shift, offset); - ESP_LOGD(tag," Strip1 Task Creating...Core: %d", core); - xTaskCreatePinnedToCore(Strip1_Control_Task, "LED_Strip1_Task", 1024*10, NULL, 1, &Strip1_Task_Handle, core); - } - - // ********** STRIP2 ******************************** - stripJson.clear(); - stripJson = doc["strip2"]; - if(jsonConstrainBool(tag, stripJson, "en", false)){ - int port = jsonConstrain(tag, stripJson, "i2s-ch", 0, 1, 0); - int size = jsonConstrain(tag, stripJson, "size", 1, 200, 10); - //int pin = jsonConstrainInt(stripJson, "pin", 0, 48, RGBLED2_Pin); - LED_ORDER order= getRGBOrder( jsonConstrainString(tag, stripJson, "rgb-order", "grb").c_str() ); - int shift = jsonConstrain(tag, stripJson, "shift", -size, size, 0); - int offset = jsonConstrain(tag, stripJson, "offset", -size, size, 0); - int core2 = jsonConstrain(tag, stripJson, "core", 0, 1, 0); - int powerDiv = jsonConstrain(tag, stripJson, "power-div", 0, 3, 0); - - strip2 = new LEDSTRIP(port, size, boardPins.rgb2, order, shift, offset); - strip2->setPowerDiv(powerDiv); - ESP_LOGI(tag,"Strip2 initialized."); - ESP_LOGD(tag," Size: %d, port: %d, shift: %d, offset: %d", size, port, shift, offset); - ESP_LOGD(tag,"Strip2 Task Creating...Core: %d", core2); - xTaskCreatePinnedToCore(Strip2_Control_Task, "LED_Strip2_Task", 1024*8, NULL, 1, &Strip2_Task_Handle, core2); - }else{ - ESP_LOGE(tag,"Strip2 disabled"); - } - - JsonObject flightJson = doc["front-light"]; - animProps.frontLight.enabled = jsonConstrainBool(tag, flightJson, "en", false); - if(animProps.frontLight.enabled){ - animProps.frontLight.relayIndex = jsonConstrain(tag, flightJson, "relay", 0, 3, 0); - animProps.frontLight.core = jsonConstrain(tag, flightJson, "core", 0, 1, 1); - animProps.frontLight.style = (FRONT_LIGHT_STYLE)(flightJson, "style", 0, 1, 0); - ESP_LOGI(tag, "Front Light initialized.."); - Init_FrontLight(); - } - - JsonObject rlightJson = doc["rear-light"]; - animProps.rearLight.enabled = jsonConstrainBool(tag, rlightJson, "en", false); - if(animProps.rearLight.enabled){ - animProps.rearLight.relayIndex = jsonConstrain(tag, rlightJson, "relay", 0, 3, 1); - animProps.rearLight.buttonIndex = jsonConstrain(tag, rlightJson, "button", 0, 2, 2); - animProps.rearLight.rampTime = jsonConstrain(tag, rlightJson, "ramp", 1000, 20000, 3000); - animProps.rearLight.rampSteps = jsonConstrain(tag, rlightJson, "steps", 2, 20, 8); - animProps.rearLight.min = jsonConstrain(tag, rlightJson, "min", 0.0f, 50.0f, 0.0f); - animProps.rearLight.max = jsonConstrain(tag, rlightJson, "max", animProps.rearLight.min, 100.0f, 100.0f); - ESP_LOGD(tag, "relay: %d, btn: %d, ramp: %d, steps: %d, min: %.2f, max: %.2f", animProps.rearLight.relayIndex, animProps.rearLight.buttonIndex, animProps.rearLight.rampTime, animProps.rearLight.rampSteps, animProps.rearLight.min, animProps.rearLight.max); - - Initialize_Rear_Control(animProps.rearLight.relayIndex, animProps.rearLight.buttonIndex, animProps.rearLight.rampTime, animProps.rearLight.rampSteps , animProps.rearLight.min, animProps.rearLight.max); - ESP_LOGI(tag, "Rear Light initialized.."); - } - - } - -} - -void Init_FrontLight(void) -{ - xTaskCreatePinnedToCore(FrontLight_Task, "FrontLight_Task", 5000, NULL, 1, &FrontLight_Task_Handle, animProps.frontLight.core); -} - -void Init_RearLight(void) -{ - //if(jsonOb.isNull()){ Serial.println(" rear_light json is Null.."); return; } -} - -void Test_Animations(void){ - ANIMATION_EVENT event; - - strip1->fill({0,0,0}, 0, strip1->effSize); - strip1->show(true); - vTaskDelay(100); - - event.hue = RGBtoHUE(col_blue); - event.hueRange = 180; - event.param1 = 11; - event.speed = 70; - - LEDStrip_FireInit(*strip1); - - while(1){ - event.hue = 0; - event.hueRange = 359; - event.param1 = 22; - event.speed = 70; - //Animation_Sectors(*strip1, event, true, DT_BOTH, true, 6, 2); - event.param1 = 30; - //Animation_Sectors(*strip1, event, true, DT_BOTH, true, 6, 2); - event.param1 = 40; - //Animation_Sectors(*strip1, event, true, DT_BOTH, true, 6, 2); - event.param1 = 50; - Animation_Sectors(*strip1, event, DT_BOTH, 2); - - event.param1 = 50; - Animation_Dashes(*strip1, event, DT_BOTH, 3); - - event.param1 = 50; - Animation_Dashes(*strip1, event, DT_BOTH, 3); - /* - Animation_Fire(*strip1, event, RED_FIRE, 5000); - Animation_Fire(*strip1, event, GREEN_FIRE, 5000); - Animation_Fire(*strip1, event, BLUE_FIRE, 5000); - - event.col1 = col_blue; - event.col2 = {255,136,0}; - event.density = 11; - event.speed = 100; - Animation_Snakes(*strip1, event, false, DT_FWD, 2, 1); - - event.col1 = HUEtoRGB(359); - event.col2 = HUEtoRGB(0); - event.density = 22; - event.speed = 70; - Animation_Snakes(*strip1, event, true, DT_BOTH, 12, 4); - - event.col1 = HUEtoRGB(359); - event.col2 = HUEtoRGB(0); - event.density = 56; - event.speed = 50; - Animation_Snakes(*strip1, event, true, DT_BOTH, 12, 4); - */ - } -} - -void Strip1_Control_Task(void *parameters) -{ - vTaskDelay(1000); // small start delay - ESP_LOGD(tag, "Strip1 Task Entered...."); - //Test_Animations(); - - LEDStrip_FireInit(*strip1); // must be initialized before calling fire animation - - // Set default event 1 animation base on profile values - ANIMATION_EVENT ev; // empty event - ev.animIndex = 0; - ev.countDown = 6000; - ev.param2 = 75; - ev.type = EV_NON_INJECT; - PostNewEvent(ev); // Start Animation (White Fill) - - animProps.event[1].type = EV_NORMAL; - PostNewEvent(animProps.event[1]); // default attraction animation - - while(true){ - xQueueReceive( eventQueue, &eventMsg, portMAX_DELAY ); - ESP_LOGD(tag, "Queue waiting: %d", uxQueueMessagesWaiting(eventQueue)); - - if(eventMsg.type == EV_NORMAL ) { // EV_NORMAL - ESP_LOGD(tag, "Running event: type: EV_NORMAL, event: %d, anim: %d", eventMsg.selfIndex, eventMsg.animIndex); - lastNormalEventMsg = eventMsg; //save last Normal EventMsg - if( eventMsg.selfIndex >= 0 ) { - CurrentRunningEventIndex = eventMsg.selfIndex; - } - - if(Luma_PeerCount() > 0){ - TempLumaPacket.type = LPT_ANIM; - memcpy(&TempLumaPacket.data, &eventMsg, sizeof(ANIMATION_EVENT)); - Luma_Master_Broadcast(TempLumaPacket); - } - - if( eventMsg.selfIndex == 0 ){ - RunWhitefillAnimation( eventMsg ); - }else{ - RunAnimation( eventMsg ); - } - } - else if( eventMsg.type == EV_INJECT ){ // insert and return to previous animation - ESP_LOGD(tag, "EV_INJECT"); - xQueueSend( eventQueue, &lastNormalEventMsg, 100 ); // requeue previous normal event - RunPopUpAnimations( eventMsg ); - } - else if( eventMsg.type == EV_NON_INJECT ){ - ESP_LOGD(tag, "EV_NON_INJECT"); - RunPopUpAnimations( eventMsg ); - } - else if( eventMsg.type == EV_TEST ){ - ESP_LOGD(tag, "EV_TEST"); - animStatus.EventTestCountdown = EVENT_TESTMODE_TIMEOUT; // start timeout countdown - // Should not re-post last event from here in case repeated tests are started. - // that would cause a backlog of the same previous event. - if( eventMsg.selfIndex == 0 ){ - RunWhitefillAnimation( eventMsg); - }else{ - RunAnimation( eventMsg ); - } - } - } -} - -void PostLastNormalEvent(){ - xQueueSend( eventQueue, &lastNormalEventMsg, 100 ); // requeue previous normal event - ESP_LOGD(tag, "RePosted Last Normal Event Index: %d", lastNormalEventMsg.selfIndex); -} - -// Used to cycle to the next event primarity when usinging buttons -int IncrementEventIndex(){ - int x = (CurrentRunningEventIndex + 1) % animStatus.EventsCount; - ESP_LOGD(tag, "Increment Event Index from %d to %d", CurrentRunningEventIndex, x); - - animProps.event[x].type = EV_NORMAL; - PostNewEvent(animProps.event[x]); - return animStatus.EventsIndex; -} - -//EVENT_MSG newEvent; -void PostNewEvent( ANIMATION_EVENT &animEvent) { - //newEvent.type = type; - //newEvent.event = animEvent; - xQueueSend(eventQueue, &animEvent, 100); // queue new event - - // if(type == EV_NORMAL){ - // If whitefill index ( could be restarted ) - // if(animEvent.animIndex == ANIM_WHITEFILL_INDEX){ - //if( countDown == 0 ) { animStatus.countDown = 1000; } // TODO Countdown calc maybe wrong...double check - //if( animStatus.busy ) { animStatus.repeat = true; } - // if( FrontLight_Task_Handle ) { xTaskNotifyGive( FrontLight_Task_Handle ); } - // } - // } - - if( Strip1_Task_Handle ){ xTaskNotifyGive( Strip1_Task_Handle ); } -} - -void Strip2_Control_Task(void *parameters) -{ - vTaskDelay(100); - ESP_LOGD(tag, "Strip2 Task Entered....\n"); - - for(;;){ - vTaskDelay(10000); - } -} - -void FrontLight_Task(void *parameters){ - animStatus.busy = false; - ANIMATION_EVENT whiteMsg; - for(;;){ - xQueueReceive( whiteQueue, &whiteMsg, portMAX_DELAY ); - - int msFillTime = 0; - if(whiteMsg.countDown > 0){ // use countdown if available - msFillTime = whiteMsg.countDown; - }else{ - msFillTime = map(whiteMsg.param1, 0, 100, 0, 10000); - if(msFillTime < 1000){ msFillTime = 1000; } - } - float delayFactor = (float)map(whiteMsg.param2, 0, 100, 0, 100) / 100.0; - Const_White_Fill(whiteStatus, animProps.frontLight, delayFactor, msFillTime, 50); - } -} - -void load_animation_profile(void){ - File file = LittleFS.open("/cfg/anim-profile-common.json"); - - if(!file){ - ESP_LOGE(tag, "Error opening anim-profile-common.json..."); - file.close(); - }else{ - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - if(error){ ESP_LOGE(tag, "anim-profile-common.json deserialize error!.."); return;} - - JsonObject frontJson = doc["countdown"]; - animProps.frontLight.minDuty = jsonConstrain(tag, frontJson, "min", 0.0f, 99.0f, 20.0f); - animProps.frontLight.maxDuty = jsonConstrain(tag, frontJson, "max", 1.0f, 100.0f, 99.0f); - animProps.frontLight.holdTime = jsonConstrain(tag, frontJson, "hold", 100, 5000, 1000); - animProps.frontLight.rampTime = jsonConstrain(tag, frontJson, "ramp", 100, 5000, 500); - - animProps.profileIndex = jsonConstrain(tag, doc.as(), "profile-index", 0, 7, 0); - - ESP_LOGI(tag, "anim-profile-common.json settings loaded."); - } -} - -void load_animation_profileByIndex(int index){ - - //for(int index = 1; index <= 8; index++){ - String strFileName = "/cfg/anim-profile" + String(index + 1) + ".json"; - File file = LittleFS.open(strFileName); - - if(!file){ - ESP_LOGE(tag, "%s", "Error opening " + strFileName); - file.close(); - }else{ - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - if(error){ ESP_LOGE(tag, "%s deserialize error!..", strFileName.c_str()); return;} - - JsonObject profJson = doc.as(); - animProps.profileName = jsonConstrainString(tag, profJson, "name", "").c_str(); - ESP_LOGD(tag, "Profile Index: %d, Name: %s", index, animProps.profileName); - - // - JsonArray eventsJson = profJson["events"]; - for(int i = 0; i < animStatus.EventsCount; i++){ - animProps.event[i].selfIndex = i; // Self Index - - if(i == 0){ - animProps.event[i].animIndex = jsonConstrain(tag, eventsJson[i], "anim", 0, animProps.whitefillsCount-1, 0); - }else{ - animProps.event[i].animIndex = jsonConstrain(tag, eventsJson[i], "anim", 0, animProps.animationsCount-1, 0); - } - - animProps.event[i].hue = jsonConstrain(tag, eventsJson[i], "hue", -2, 360, 0); - animProps.event[i].hueRange = jsonConstrain(tag, eventsJson[i], "hue-range", 0, 360, 1); - animProps.event[i].speed = jsonConstrain(tag, eventsJson[i], "speed", 0, 100, 50); - animProps.event[i].param1 = jsonConstrain(tag, eventsJson[i], "param1", 0, 100, 50); - animProps.event[i].param2 = jsonConstrain(tag, eventsJson[i], "param2", 0, 100, 50); - animProps.event[i].check1 = jsonConstrainBool(tag, eventsJson[i], "check1", false); - animProps.event[i].check2 = jsonConstrainBool(tag, eventsJson[i], "check2", false); - animProps.event[i].check3 = jsonConstrainBool(tag, eventsJson[i], "check3", false); - animProps.event[i].check4 = jsonConstrainBool(tag, eventsJson[i], "check4", false); - - ESP_LOGD(tag, " self: %d, anim: %d, param1: %d, speed: %d", animProps.event[i].selfIndex, animProps.event[i].animIndex, animProps.event[i].param1, animProps.event[i].speed); - } - ESP_LOGI(tag, "%s settings loaded.", strFileName.c_str()); - } - //} -} - -void RunWhitefillAnimation(ANIMATION_EVENT &event){ - //Start Constant Light Task if available - if( FrontLight_Task_Handle ){ - xQueueSend(whiteQueue, &event, 100); // queue new event - xTaskNotifyGive( FrontLight_Task_Handle ); - } - - int ret; - switch(event.animIndex){ - case 0: // Bottom/Up Fill - ESP_LOGD(tag, " Running WhiteFill: %d , bottom/up", event.animIndex); - ret = Animation_White_Fill_Mirrored(*strip1, event); - break; - case 1: // Snake Fill - ESP_LOGD(tag, " Running WhiteFill: %d , Snake fill", event.animIndex); - ret = Animation_White_Fill_Mirrored(*strip1, event); - break; - case 2: // Tick Fill - ESP_LOGD(tag, " Running WhiteFill: %d , Tick fill", event.animIndex); - ret = Animation_White_Fill_Mirrored(*strip1, event); - break; - case 3: // Smooth Brighten - ESP_LOGD(tag, " Running WhiteFill: %d , Smooth Brighten", event.animIndex); - ret = Animation_White_Fill_Mirrored(*strip1, event); - break; - case 4: // Cycle All - ESP_LOGD(tag, " Running WhiteFill: %d , Cycle All", event.animIndex); - ret = Animation_White_Fill_Mirrored(*strip1, event); - break; - default: // Random Select - ESP_LOGD(tag, " Running WhiteFill: default , bottom/up"); - ret = Animation_White_Fill_Mirrored(*strip1, event); - break; - } - - // if exited loop naturally... not from a notification so keep waiting - if(ret == EXIT_FINISHED || ret == EXIT_TIMEOUT){ - ESP_LOGD(tag, "Whitefill normal exit... waiting"); - ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); - } -} - -void RunAnimation(ANIMATION_EVENT &event){ - if(event.animIndex < 80){ - switch(event.animIndex){ // AnimationEventIndex (0-X) - case 0: // Rainbow - ESP_LOGD(tag, " Running Anim: %d , Rainbow", event.animIndex); - Animation_Rainbow(*strip1, event, INFINITE_LOOP); - break; - case 1: // Hue Spectrum Mirrored - ESP_LOGD(tag, " Running Anim: %d , Hue Spectrum Mirrored", event.animIndex); - Animation_Hue_Spectrum_Mirrored(*strip1, event, INFINITE_LOOP); - break; - case 2: // Color Pulse Cycle - ESP_LOGD(tag, " Running Anim: %d , Color Pulse Cycle", event.animIndex); - Animation_Pulse_Color_Cycling(*strip1, event); - break; - case 3: // Comets Mixed Colors - ESP_LOGD(tag, " Running Anim: %d , Comets", event.animIndex); - Animation_Comets(*strip1, event, DT_BOTH, INFINITE_LOOP); - break; - case 4: // Dashes Single and Mixed Colors - ESP_LOGD(tag, " Running Anim: %d , Dashes", event.animIndex); - Animation_Dashes(*strip1, event, DT_BOTH, INFINITE_LOOP); - break; - case 5: // Snakes Single and Mixed Colors - ESP_LOGD(tag, " Running Anim: %d , Snakes", event.animIndex); - Animation_Snakes(*strip1, event, DT_BOTH, INFINITE_LOOP); - break; - case 6: // Sectors Mixed Colors (No Sigle Colors because pointless) - ESP_LOGD(tag, " Running Anim: %d , Sectors", event.animIndex); - Animation_Sectors(*strip1, event, DT_BOTH, INFINITE_LOOP); - break; - case 7: // Fire (Red) - ESP_LOGD(tag, " Running Anim: %d , Fire", event.animIndex); - Animation_Fire(*strip1, event); - break; - case 8: // - break; - case 9: // Color Strobing - break; - case 10: // Random Color Twinkle - break; - case 11: // Stacking - break; - case 12: // Rain - break; - case 13: // Stacking - break; - case 14: // RED/WHITE/BLU Flag (density selects color pallet) (sector/comets,dashes, snakes) - break; - case 15: - break; - default: - break; - } - }else{ // Non Looping Functions - switch(event.animIndex){ // AnimationEventIndex (0-X) - case 80: // clear strip - strip1->fill(col_black, 0, strip1->effSize); - strip1->show(true); - ESP_LOGD(tag, "Animation Strip1 Clear"); - ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); - break; - case 81: // set pixel - strip1->setPixel(event.param1, GetColorFromHue(event.hue)); - strip1->show(true); - ESP_LOGD(tag, "Animation Set Pixel: %d", event.param1); - ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); - break; - case 82: // - break; - default: - break; - } - } - -} - -// These animations should be quick and not infinite -void RunPopUpAnimations(ANIMATION_EVENT &event){ - - switch(event.animIndex){ // AnimationEventIndex (0-X) - case 0: // Start/Boot/Power Up Sequence - ANIMATION_EVENT ev; - ev.animIndex = 0; - ev.hue = -1; //{200, 200, 200}; //col_white; - ev.hueRange = 1; //col_black; - ev.countDown = 6000; // 6 seconds - ev.param2 = 75; - if( FrontLight_Task_Handle ){ - xQueueSend(whiteQueue, &ev, 100); // queue new event - xTaskNotifyGive( FrontLight_Task_Handle ); - } - Animation_White_Fill_Mirrored(*strip1, ev); - - break; - case 1: // BLE Connected - break; - case 2: // BLE Disconnected - break; - case 3: // WiFi Connected - break; - case 4: // WiFi Disconnected - break; - case 5: // Luma Stick Connected - break; - default: - break; - } - -} - - - -// json color to rgbPixel conversion -// Unused now -rgbpixel_t hexToRGB(const char* hexColor) { - long hexValue = strtol(hexColor + 1, nullptr, 16); // Skip the '#' character - rgbpixel_t pix; - pix.red = (hexValue >> 16) & 0xFF; - pix.grn = (hexValue >> 8) & 0xFF; - pix.blu = hexValue & 0xFF; - return pix; -} - - - - diff --git a/temporary/Temp/led_strip.h b/temporary/Temp/led_strip.h deleted file mode 100644 index 3f363fa..0000000 --- a/temporary/Temp/led_strip.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef _LED_STRIP_H -#define _LED_STRIP_H - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "common/LEDStrip.h" -#include -#include "my_board.h" - -extern LEDSTRIP *strip1; -extern LEDSTRIP *strip2; -extern TaskHandle_t Strip1_Task_Handle; -extern TaskHandle_t Strip2_Task_Handle; -extern TaskHandle_t FrontLight_Task_Handle; - -#define ANIM_WHITEFILL_INDEX 0 -#define ANIM_DEFAULT_INDEX 1 -#define ANIM_EVENT_SIZE 12 -#define PROFILES_SIZE 8 - -#define MIN_LED_UPDATE_INTERVAL 13 - -enum OtherANIMS { OA_SET_PIXEL=100, OA_CLEAR, }; - -enum FRONT_LIGHT_STYLE { FRONT_LIKE_LUMIA, FRONT_LIKE_ROAMER }; - -enum EVENT_TYPE { EV_NORMAL, EV_INJECT, EV_NON_INJECT, EV_TEST,}; - -// Single web page event (upto 8) -typedef struct{ - EVENT_TYPE type; - int selfIndex; - int animIndex; - int hue; - int hueRange; - int speed; - int param1; - int param2; - bool check1; - bool check2; - bool check3; - bool check4; - int countDown; -}ANIMATION_EVENT; - -typedef struct{ - bool enabled; - uint8_t relayIndex; - uint8_t core; - int holdTime; - int rampTime; - float minDuty; - float maxDuty; - FRONT_LIGHT_STYLE style; - //float delayFactor; -}FRONT_LIGHT; - -typedef struct{ - bool enabled; - uint8_t relayIndex; - uint8_t buttonIndex; - uint8_t core; - int rampTime; - uint8_t rampSteps; - float min; - float max; -}REAR_LIGHT; - - -typedef struct { - EVENT_TYPE type; - ANIMATION_EVENT event; -}EVENT_MSG; - -// Properties from webpage -typedef struct { - int profileIndex; - const char* profileName; - int whitefillsCount; - int animationsCount; - FRONT_LIGHT frontLight; - REAR_LIGHT rearLight; - ANIMATION_EVENT event[ANIM_EVENT_SIZE]; -}ANIMATION_PROPS; - -extern ANIMATION_PROPS animProps; - -enum POPUP_ANIM { POP_STATUP, POP_BLE_CONN, POP_BLE_DISC, POP_WIFI_CONN, POP_WIFI_DISC, POP_STICK_CONN, POP_STICK_DISC }; - -void RunWhitefillAnimation(ANIMATION_EVENT &event); - -void RunAnimation(ANIMATION_EVENT &event); - -void RunPopUpAnimations(ANIMATION_EVENT &event); - -//void SetEventIndex(int index, int countdown=0, bool test=false); - -//void PostNewEvent( int countDown, EVENT_TYPE type, ANIMATION_EVENT &animEvent); -void PostNewEvent( ANIMATION_EVENT &animEvent); - -int IncrementEventIndex(void); - -void PostLastNormalEvent(void); - -void load_animation_profile(void); // cfg/anim-profiles.json -void load_animation_profileByIndex(int); // cfg/anim-profileX.json - -void Init_LED_Devices(BOARD_PINS); // cfg/led-devices.json - -rgbpixel_t hexToRGB(const char* hexColor); - -//void Init_LEDStrip2(void); - -void Init_FrontLight(void); - -//void Init_RearLight(void); - -void Strip1_Control_Task(void *parameters); - -void Strip2_Control_Task(void *parameters); - -void FrontLight_Task(void *parameters); - - - - - -#endif diff --git a/temporary/Temp/lights-old.html b/temporary/Temp/lights-old.html deleted file mode 100644 index 62a71d5..0000000 --- a/temporary/Temp/lights-old.html +++ /dev/null @@ -1,755 +0,0 @@ -{{NAVBAR}} - - - - App Control Configuration - - - - - - -

App Control Configuration

- -
- Saved Animation Profiles - - - - -
-
- - -    - - -     - -
-
- - -
- - -
- Countdown ( Constant Light ) - - - - - - - - - - - - - - -
-
- -
-
- -
- -
-
-
-
- -
-
- -
-
-
-
- -
- -
- Event0 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event1 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event2 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event3 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event4 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event5 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event6 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event7 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event8 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event9 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- - -
- -
- Event10 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- -
- -
- Event11 - - - - - - - - - -
-
- -
-
-   -
-
-   -
-
- -
-
- -
- -
-
- - - - diff --git a/temporary/Temp/log.html b/temporary/Temp/log.html deleted file mode 100644 index 8684117..0000000 --- a/temporary/Temp/log.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - System Log - - -

System Log

- - \ No newline at end of file diff --git a/temporary/Temp/luma_master.cpp b/temporary/Temp/luma_master.cpp deleted file mode 100644 index 7ec642a..0000000 --- a/temporary/Temp/luma_master.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "luma_master.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include -#include -#include "JsonConstrain.h" -#include -#include -#include "global.h" - -static const char* tag = "lumaM"; -uint8_t broadcastAddress[] = {0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF}; -uint8_t availableStiks = 0; -LUMA_NODE lumaStation[LUMA_NODE_MAX_COUNT]; -bool LUMASTIKS_READY = false; - -TaskHandle_t LumaMaster_Task_Handle; - -bool SendRegistrationPacket = false; -LUMA_PACKET RegistrationPacket; -esp_now_peer_info_t TempNode; - - - -QueueHandle_t lumaQueue = xQueueCreate( 4, sizeof( LUMA_PACKET ) ); - -void Init_Luma_Master(void){ - - if (esp_now_init() != ESP_OK) { - ESP_LOGD(tag, "Error initializing ESP-NOW\n"); - return; - } - - xTaskCreatePinnedToCore(LumaMaster_Task, "LumaMaster_Task", 1024*6, NULL, 1, &LumaMaster_Task_Handle, CONFIG_ARDUINO_RUNNING_CORE); - ESP_LOGV(tag, "Initialized LumaMaster task created..."); - - esp_now_register_recv_cb(Luma_Master_Data_Received); - esp_now_register_send_cb(Luma_Master_Data_Sent); -} - -void LumaMaster_Task(void *parameters){ - - while(1){ - vTaskSuspend(NULL); - - if(SendRegistrationPacket){ - Luma_Send_Packet(TempNode.peer_addr, RegistrationPacket); - } - } - - - LUMA_PACKET lumaPacket; - - while(1){ - xQueueReceive( lumaQueue, &lumaPacket, portMAX_DELAY ); - - switch(lumaPacket.type){ - case LPT_RAW: - break; - case LPT_REG: - Luma_Send_Packet(TempNode.peer_addr, lumaPacket); - break; - case LPT_ANIM: - Luma_Master_Broadcast(lumaPacket); - break; - default: - break; - } - } -} - -void Luma_Master_Data_Sent(const uint8_t *mac_addr, esp_now_send_status_t status){ - -} - -void Luma_Master_Data_Received(const uint8_t *mac, const uint8_t *data, int len){ - - LUMA_PACKET *packet = (LUMA_PACKET*)data; - - printf("** Data Received **\n\n"); - printf("Received from MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - printf("Length: %d byte(s)\n", len); - printf("Data: %d\n\n", data[0]); - - switch(packet->type){ - case LPT_RAW: - break; - case LPT_REG: - LUMA_REGISTER_PACKET *reg = (LUMA_REGISTER_PACKET*)&packet->data; - ESP_LOGD(tag, "Node SSID: %s", reg->ssid); - - // Register - memcpy(TempNode.peer_addr, mac, 6); - TempNode.channel = WiFi.channel(); - Luma_Add_Peer(TempNode); - - // Notify Peer - RegistrationPacket.type = LPT_REG; - xQueueSend( lumaQueue, &RegistrationPacket, 100 ); - break; - //default: - // break; - } -} - -void Luma_Master_Broadcast(LUMA_PACKET packet){ - -} - - diff --git a/temporary/Temp/luma_master.h b/temporary/Temp/luma_master.h deleted file mode 100644 index 5808f26..0000000 --- a/temporary/Temp/luma_master.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _LUMA_MASTER_H -#define _LUMA_MASTER_H - -#include -#include -#include "common/luma-stiks.h" - - -extern bool LUMASTIKS_READY; - -#define LUMA_NODE_MAX_COUNT 16 -//extern LUMA_NODE lumaStation[]; - -void LumaMaster_Task(void *parameters); - -void Init_Luma_Master(void); - -void Luma_Master_Data_Received(const uint8_t *mac, const uint8_t *data, int len); - -void Luma_Master_Data_Sent(const uint8_t *mac_addr, esp_now_send_status_t status); - -void Luma_Master_Broadcast(LUMA_PACKET packet); - -#endif \ No newline at end of file diff --git a/temporary/Temp/my_wifi.cpp b/temporary/Temp/my_wifi.cpp deleted file mode 100644 index 12ec314..0000000 --- a/temporary/Temp/my_wifi.cpp +++ /dev/null @@ -1,1451 +0,0 @@ - -/* - wifi is started in STATION mode and tries to connected to AP saved - in the creds.json file. It will keep trying to connect forever. If - it connects then the board LEDS will toggle, the buzzer will play a tune - and the IP address will be sent to the serial port. Also the device will - be discoverable as "http://atadev.local/" - - If credentials need to be changed then double reset can be done to - trigger the AP mode and a wifi config page will be available on address - 192.168.4.1. Credentials can be entered and applied then you can reset - the device so it connects with the correct credentials. - -*/ -#include "my_wifi.h" - -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "global.h" -#include -#include "my_buzzer.h" -#include "my_board.h" -#include "common/led_animation.h" -#include "led_strip.h" -#include "common/fileSystem.h" -#include "JsonConstrain.h" -#include "led_strip.h" -#include "my_oled.h" -#include "BTSerial.h" -#include "esp_log.h" - -#include "firmware_html.h" - -int RebootSystem = 0; -#define WIFI_TIMEOUT_MS 10000 - -static const char* tag = "wifi"; - -bool WifiClientConnected = false; -AsyncWebServer webServer(80); -DNSServer *dnsServer; -#define DNS_PORT 53 - -#define StartDelayedRebooth RebootSystem = 1000/BUTTON_UPDATE_PERIOD; // start reboot countdown for 1sec - -String ssid; -String passPhrase; - -String AP_SSID; -String AP_Pass; -String mDnsName; -String HostName; - -IPAddress local_IP(192,168,10,1); -IPAddress gateway(192,168,10,200); -IPAddress subnet(255,255,255,0); - -// for file manager page -String filesDropdownOptions((char*)0); -String dirDropdownOptions((char*)0); -String savePath((char*)0); // needed for storing file when editing a file -String savePathInput((char*)0); -const char* http_username = "admin"; -const char* http_password = "admin"; -const char* param_delete_path = "delete-path"; -const char* param_edit_path = "edit-path"; -const char* param_dir_pad = "dir-path"; -const char* param_edit_textarea = "edit-textarea"; -const char* param_save_path = "save-path"; -String allowedExtensionsForEdit = "txt, h, htm, html, css, cpp, js, json, ini, cfg"; -//const char* jquery = "/jquery-3.6.3.min.js"; - -void Init_Wifi_Task(void) -{ - File file = LittleFS.open("/cfg/wifi.json", "r"); - if(!file){ - ESP_LOGE(tag, "Failed to open wifi.json!"); - file.close(); - return; - } - - // Parse the JSON file - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - if(!error){ - JsonObject wifiJson = doc["wifi"]; - file.close(); - mDnsName = jsonConstrainString(tag, wifiJson,"mdns-name", "atadev"); - ESP_LOGD(tag, "mDnsName: %s", mDnsName.c_str()); - - if(jsonConstrainBool(tag, wifiJson, "en", false)){ - JsonObject j = doc["cred1"]; - Wifi_Read_Credentials( j ); - xTaskCreatePinnedToCore(Wifi_Task, "Wifi_Task", 1024*10, NULL, 1, NULL, CONFIG_ARDUINO_RUNNING_CORE); - ESP_LOGD(tag, "Initialized WiFi (task created)..."); - } - - JsonObject ap = doc["ap"]; - AP_SSID = jsonConstrainString(tag, ap, "ssid", "ATA_AP"); - if(jsonConstrainBool(tag, ap, "append-id", true)){ - String macHex = String(chipInfo.macByte[1], HEX) + String(chipInfo.macByte[0], HEX); - AP_SSID += "_"; - macHex.toUpperCase(); - AP_SSID += macHex; - } - AP_Pass = jsonConstrainString(tag, ap, "pass", "12345678"); - }else{ - ESP_LOGE(tag, "Deserialization error for wifi.json"); - } -} - -void onWiFiEvent(WiFiEvent_t event) -{ - //Serial.printf("[WiFi-event] event: %d\n", event); - switch (event) { - case ARDUINO_EVENT_WIFI_READY: - //Serial.println("WiFi interface ready"); - break; - case ARDUINO_EVENT_WIFI_SCAN_DONE: - //Serial.println("Completed scan for access points"); - break; - case ARDUINO_EVENT_WIFI_STA_START: - //Serial.println("WiFi client started"); - break; - case ARDUINO_EVENT_WIFI_STA_STOP: - //Serial.println("WiFi clients stopped"); - break; - case ARDUINO_EVENT_WIFI_STA_CONNECTED: - WifiClientConnected = true; - //Serial.println("Connected to access point"); - break; - case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: - WifiClientConnected = false; - ESP_LOGI(tag,"WiFi Disconnected"); - //Buzzer_Play_Tune(TUNE_WIFI_DISCONNECTED); - break; - case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: - //Serial.println("Authentication mode of access point has changed"); - break; - case ARDUINO_EVENT_WIFI_STA_GOT_IP: - ESP_LOGI(tag,"My IP: %s", WiFi.localIP().toString()); - Wifi_Start_MDNS(); - Buzzer_Play_Tune(TUNE_WIFI_CONNECTED); - break; - case ARDUINO_EVENT_WIFI_STA_LOST_IP: - //Serial.println("Lost IP address and IP address is reset to 0"); - break; - case ARDUINO_EVENT_WPS_ER_SUCCESS: - //Serial.println("WiFi Protected Setup (WPS): succeeded in enrollee mode"); - break; - case ARDUINO_EVENT_WPS_ER_FAILED: - //Serial.println("WiFi Protected Setup (WPS): failed in enrollee mode"); - break; - case ARDUINO_EVENT_WPS_ER_TIMEOUT: - // Serial.println("WiFi Protected Setup (WPS): timeout in enrollee mode"); - break; - case ARDUINO_EVENT_WPS_ER_PIN: - //Serial.println("WiFi Protected Setup (WPS): pin code in enrollee mode"); - break; - case ARDUINO_EVENT_WIFI_AP_START: - //Serial.println("WiFi access point started"); - break; - case ARDUINO_EVENT_WIFI_AP_STOP: - //Serial.println("WiFi access point stopped"); - break; - case ARDUINO_EVENT_WIFI_AP_STACONNECTED: - //Serial.println("Client connected"); - break; - case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED: - ESP_LOGI(tag,"SoftAP Client Disconnected"); - //Buzzer_Play_Tune(TUNE_WIFI_DISCONNECTED); - break; - case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED: - ESP_LOGI(tag,"SoftAP Client Connected"); - Buzzer_Play_Tune(TUNE_WIFI_CONNECTED); - break; - case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED: - //Serial.println("Received probe request"); - break; - case ARDUINO_EVENT_WIFI_AP_GOT_IP6: - //Serial.println("AP IPv6 is preferred"); - break; - case ARDUINO_EVENT_WIFI_STA_GOT_IP6: - //Serial.println("STA IPv6 is preferred"); - break; - case ARDUINO_EVENT_ETH_GOT_IP6: - //Serial.println("Ethernet IPv6 is preferred"); - break; - case ARDUINO_EVENT_ETH_START: - //Serial.println("Ethernet started"); - break; - case ARDUINO_EVENT_ETH_STOP: - //Serial.println("Ethernet stopped"); - break; - case ARDUINO_EVENT_ETH_CONNECTED: - //Serial.println("Ethernet connected"); - break; - case ARDUINO_EVENT_ETH_DISCONNECTED: - //Serial.println("Ethernet disconnected"); - break; - case ARDUINO_EVENT_ETH_GOT_IP: - // Serial.println("Obtained IP address"); - break; - default: break; - } -} - -void Wifi_Task(void *parameters) -{ - // Extend watchdog timer - esp_task_wdt_init(2, false); - - Setup_WebServer_Handlers(&webServer); - WiFi.onEvent(onWiFiEvent); - WiFi.setHostname(mDnsName.c_str()); - WiFi.softAPConfig(local_IP, gateway, subnet); - WiFi.softAP(AP_SSID.c_str(), AP_Pass.c_str()); - Wifi_Start_MDNS(); - vTaskDelay(100); - webServer.begin(); - - // Choose WIFI Mode - if(commMode == COMM_WIFI_AP_BLE){ // AP Only - WiFi.mode(WIFI_AP); - while(1){ vTaskDelay(500 / portTICK_PERIOD_MS); } - }else{ // AP & Client (dslrbooth) - esp_wifi_set_ps(WIFI_PS_NONE); - WiFi.mode(WIFI_AP_STA); - Wifi_Client_Loop(); - } -} - -void Wifi_Client_Loop(){ - while(true){ - // Wifi status check loop - if(WiFi.status() == WL_CONNECTED){ - vTaskDelay(250); - continue; - } - - // Start WiFi Client - ESP_LOGD(tag, "Wifi trying stored creds: %s..%s",ssid.c_str(), passPhrase.c_str()); - WiFi.begin(ssid.c_str(), passPhrase.c_str()); - - //Wait until connected or timeout - ESP_LOGV(tag, "WiFi Connecting..."); - unsigned long startAttemptTime = millis(); - while(WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < WIFI_TIMEOUT_MS){ - vTaskDelay(100 / portTICK_PERIOD_MS); - } - - // Delay if wifi connection fails and continue - if(WiFi.status() != WL_CONNECTED){ - ESP_LOGW(tag, "WIFI Connection Failed!"); - for(int i = 0; i < WIFI_TIMEOUT_MS/100; i++){ - vTaskDelay(100); - } - continue; - } - } -} - -void Wifi_Start_MDNS(void) -{ - ESP_LOGV(tag, "Initializing MDNS: %s", mDnsName.c_str()); - if (!MDNS.begin(mDnsName.c_str())) { - ESP_LOGE(tag, "Error setting up MDNS responder!"); - }else{ - ESP_LOGV(tag, "You can access device via http://%s.local", mDnsName); - } -} - -void Wifi_Read_Credentials(const JsonObject &credJson){ - if(credJson.isNull()){ // set generic defaults on error - ESP_LOGE(tag, "Failed to find wifi key"); - - ssid = "Generic"; - passPhrase = "password"; - //strncpy(ssid, "Generic", sizeof(ssid)-1); - //strncpy(passPhrase, "password", sizeof(passPhrase)-1); - return; - } - else{ - // TODO Restore String - ssid = jsonConstrainString(tag, credJson, "ssid", "default"); - passPhrase = jsonConstrainString(tag, credJson, "pass", "password"); - //strncpy(ssid, jsonConstrainString(tag, credJson, "ssid", "default").c_str(), sizeof(ssid)-1); - //strncpy(passPhrase, jsonConstrainString(tag, credJson, "pass", "password").c_str(), sizeof(passPhrase)-1); - } -} - -void Wifi_Save_Credentials(String newSSID, String newPass) -{ - // Open the credentials file writing - File credsFile = LittleFS.open("/cfg/wifi.json", "r+"); - if(!credsFile){ - ESP_LOGE(tag, "Failed to open wifi.json\n"); - return; - } - - // Parse the JSON file - JsonDocument doc; - DeserializationError error = deserializeJson(doc, credsFile); - if(!error){ - JsonObject cred1Json = doc["cred1"].to(); - - if(cred1Json){ - cred1Json["ssid"] = newSSID; - cred1Json["pass"] = newPass; - - // Clear file contents before saving the modified JSON - credsFile.seek(0); - - int written = serializeJson(doc, credsFile); // save to file - ESP_LOGD(tag, "Credentials saved... ssid: %s, pass: %s, size written: %d", newSSID, newPass, written); - } - credsFile.close(); - }else{ - ESP_LOGE(tag, "Deserialization error for wifi.json"); - } -} - -void Setup_WebServer_Handlers(AsyncWebServer* serv) -{ - serv->on("/dslrbooth", HTTP_GET, handleGET_DSLRBooth); - - serv->on("/", HTTP_GET, [](AsyncWebServerRequest *request){ - if(WiFi.getMode() == WIFI_AP && !WifiClientConnected){ - request->redirect("/wifi"); - }else{ - request->redirect("/home"); - } - }); - serv->on("/home", HTTP_GET, [](AsyncWebServerRequest *request){ - sendHtmlFile("/www/home.html", request, HomeHtmlProcessor); - }); - serv->on("/lights", HTTP_GET, [](AsyncWebServerRequest *request){ - sendHtmlFile("/www/lights.html", request, htmlProcessor); - }); - serv->on("/setup", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - sendHtmlFile("/www/setup.html", request, htmlProcessor); - }); - serv->on("/wifi", HTTP_GET, [](AsyncWebServerRequest *request){ - if(WiFi.getMode() == WIFI_MODE_APSTA){ - // TODO Disable navigation bar - } - sendHtmlFile("/www/wifi.html", request, htmlProcessor); - }); - serv->on("/files", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - sendHtmlFile("/www/files.html", request, htmlProcessor); - }); - serv->on("/upload", HTTP_POST, [](AsyncWebServerRequest *request) { request->send(200); }, handlePOST_Upload); - - serv->on("/download", HTTP_GET, [](AsyncWebServerRequest *request){ - if (request->hasParam("file")) { - String filename = request->getParam("file")->value(); - if (LittleFS.exists(filename)) { - fs::File file = LittleFS.open(filename, "r"); - if (file) { - request->send(LittleFS, filename, "application/octet-stream"); - file.close(); - return; - } - } - } - request->send(404, "text/plain", "File not found!"); - }); - serv->on("/delete", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - - String filename = request->getParam(param_delete_path)->value(); - if(filename !="choose"){ - LittleFS.remove(filename.c_str()); - ESP_LOGD(tag, "Deleted file: %s", filename.c_str()); - } - - request->redirect("/files"); - }); - serv->on("/edit", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - - String fileName = request->getParam(param_edit_path)->value(); - if(fileName =="new"){ - savePath = "/new.txt"; - } - else{ - savePath = fileName; - } - - ESP_LOGD(tag, "Edit file: %s", savePath.c_str()); - sendHtmlFile("/www/edit.html", request, htmlProcessor); - }); - serv->on("/save", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - String inputMessage((char*)0); - if (request->hasParam(param_edit_textarea)) { - inputMessage = request->getParam(param_edit_textarea)->value(); - } - if (request->hasParam(param_save_path)) { - savePath = request->getParam(param_save_path)->value(); - } - writeFile(LittleFS, savePath.c_str(), inputMessage.c_str()); - - request->redirect("/files"); - }); - serv->on("/update", HTTP_POST, handlePOST_Update, updateCallback); - - // Request Data - serv->on("/get", HTTP_GET, handleGET_Get); - // Post Data - serv->on("/post", HTTP_POST, handlePOST_Post, postFileUpload, postBody); - - serv->on("/generate_204", HTTP_GET, [](AsyncWebServerRequest *request){ - ESP_LOGD(tag, "/generate_204 ... redirect to /wifi"); - request->redirect("/wifi"); - }); - - serv->on("/hotspot-detect.html", HTTP_GET, [](AsyncWebServerRequest *request){ - ESP_LOGD(tag, "/hotspot-detect.html ... redirect to /wifi"); - request->redirect("/wifi"); - }); - - serv->on("/msftconnecttest.txt", HTTP_GET, [](AsyncWebServerRequest *request){ - ESP_LOGD(tag, "/msftconnecttest.txt ... redirect to /wifi"); - request->redirect("/wifi"); - }); - - serv->on("/reg-stick", HTTP_POST, handlePOST_RegStick); - - serv->on("/firmware", HTTP_GET, [](AsyncWebServerRequest *request){ - request->send_P(200, "text/html", firmware_html_page); - }); - - serv->onNotFound([](AsyncWebServerRequest *request){ - if(WiFi.getMode() == WIFI_MODE_APSTA){ - ESP_LOGD(tag, "OnNotFound Redirect to /wifi"); - request->redirect("/wifi"); - }else if(WiFi.getMode() == WIFI_MODE_AP){ - ESP_LOGD(tag, "OnNotFound Redirect to /home"); - request->redirect("/home"); - }else{ - request->send(404); - } - }); - - serv->on("/*", HTTP_GET, handleGET_SendFile); // send any file - -} - -void handlePOST_RegStick(AsyncWebServerRequest *request){ - -} - -bool getpostSuccess = false; -// -void handleGET_Get(AsyncWebServerRequest *request){ - if(request->hasParam("type", false, false)) { - const char* dataType = request->getParam("type", false, false)->value().c_str(); - - if(!strcmp(dataType, "app-events")){ // send json file - request->send(LittleFS, "/cfg/app-events.json", "application/json"); - return; - } - - if(!strcmp(dataType, "anim-profiles")){ // send json file - request->send(LittleFS, "/cfg/anim-profiles.json", "application/json"); - return; - } - - if(!strcmp(dataType, "anim-list")){ - request->send(LittleFS, "/cfg/anim-list.json", "application/json"); - return; - } - - if(!strcmp(dataType, "sys-summary")){ - JsonDocument doc; - CreateSysSummmaryPacket(doc); - String summary; - serializeJson(doc, summary); - request->send(200, "application/json", summary); - return; - } - - if(!strcmp(dataType, "wifi")){ - JsonDocument jsdoc; - jsdoc["ssid"] = ssid; - //jsdoc["pass"] = (int)strlen(passPhrase); - jsdoc["pass"] = passPhrase; - - String jsStr; - serializeJson(jsdoc, jsStr); - - request->send(200, "application/json", jsStr); - return; - } - } - - request->send(400, "text/plain", "Failed"); -} - -void CreateSysSummmaryPacket(JsonDocument &doc){ - JsonObject booth = doc["booth"].to(); - booth["mode"] = ""; - booth["app"] = sysProps.appName; - booth["strip1"] = (strip1) ? true : false, - booth["strip2"] = (strip2) ? true : false, - booth["front-light"] = true; - booth["rear-light"] = false; - booth["oled"] = (oled) ? true : false; - - //ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getHeapSize()-ESP.getFreeHeap()); - - JsonObject Temperature = doc["temperature"].to(); - Temperature["temp"] = sysProps.t_sensor.temperature; - Temperature["sp1"] = sysProps.t_sensor.Setpoint1; - doc["system"]["firm-ver"] = FIRMWARE_VER; - - JsonObject chip = doc["chip"].to(); - chip["flash-size"] = ""; - chip["flash-free"] = ""; - chip["ram-size"] = ESP.getHeapSize(); - chip["ram-free"] = ESP.getFreeHeap(); - - - - // Get the Wi-Fi RSSI - wifi_ap_record_t wifi_ap_info; - esp_err_t rssi_result = esp_wifi_sta_get_ap_info(&wifi_ap_info); - int rssi = 0; int wifi_ch = 0; - String encryp = ""; - if (rssi_result == ESP_OK) { - rssi = wifi_ap_info.rssi; - wifi_ch = wifi_ap_info.primary; - - wifi_auth_mode_t auth_mode = wifi_ap_info.authmode; - switch (auth_mode) { - case WIFI_AUTH_OPEN: - encryp = "Open"; - break; - case WIFI_AUTH_WEP: - encryp = "WEP"; - break; - case WIFI_AUTH_WPA_PSK: - encryp = "WPA_PSK"; - break; - case WIFI_AUTH_WPA2_PSK: - encryp = "WPA2_PSK"; - break; - case WIFI_AUTH_WPA_WPA2_PSK: - encryp = "WPA_WPA2_PSK"; - break; - case WIFI_AUTH_WPA2_ENTERPRISE: - encryp = "WPA2_ENT"; - break; - default: - encryp = "UNKNOWN"; - break; - } - } - - JsonObject wifi = doc["wifi"].to(); - wifi["client-ip"] = "XXX.XXX.XXX.XXX"; - wifi["mac-addr"] = chipInfo.macStr; - wifi["ch"] = wifi_ch; - wifi["rssi"] = rssi; - wifi["encryp"] = encryp; - - JsonObject ble = doc["ble"].to(); - ble["en"] = (sysProps.appIndex == DSLRBOOTH_INDEX)? false : true; - ble["clients"] = (BTDeviceConnected)? 1 : 0; - ble["ssid"] = BLEDeviceName; - -} - -void handlePOST_Post(AsyncWebServerRequest *request){ - ESP_LOGD(tag, "posts request.."); - if(!getpostSuccess) { request->send(400, "text/plain", "Error"); } - - request->send(200, "text/plain", "Ok"); -} - -void postFileUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) { - getpostSuccess = false; - Serial.println("post file"); -} - - -// POST Requests -int packets, postTotal; -char postType[24]; -char *postData; -void postBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){ - if (!index){ - packets = 0; - int sectors = (total + 1023 + 64) / 1024; - postData = new char[1024 * sectors]; - } - - // Accumulate Data Chunks - memcpy(postData + index, data, len); - packets++; - - if((index + len) >= total){ - ESP_LOGD(tag, "index: %d, len: %d, total: %d", index, len, total); - ESP_LOGD(tag, "packets: %d", packets); - getpostSuccess = false; - - // Check if the request contains the necessary parameters - if (request->hasParam("type", false, false)) { - const char* dataType = request->getParam("type", false, false)->value().c_str(); - ESP_LOGD(tag, "data type: %s", dataType); - - if(!strcmp(dataType, "anim-profile-common") || !strcmp(dataType, "set-countdown")){ - JsonDocument profJson; - DeserializationError error = deserializeJson(profJson, postData, total); - - if(!error){ - animProps.profileIndex = profJson["profile-index"].as(); - - JsonObject countdownJson = profJson["countdown"]; - animProps.frontLight.minDuty = countdownJson["min"].as(); - animProps.frontLight.maxDuty = countdownJson["max"].as(); - animProps.frontLight.holdTime = countdownJson["hold"].as(); - animProps.frontLight.rampTime = countdownJson["ramp"].as(); - - int indexChanged = animProps.profileIndex - countdownJson["profile-index"].as(); - animProps.profileIndex = countdownJson["profile-index"].as(); - if(indexChanged){ - load_animation_profileByIndex(animProps.profileIndex); - } - - // Save to disk/flash - if(dataType[0] == 'a'){ - if(updateJsonDocument(profJson, "/cfg/anim-profile-common.json")){ - Buzzer_Beep(150, 3000); - } - } - else{ - ESP_LOGD(tag, "Post:set-countdown, index: %d, min: %.1f, max: %.1f, hold: %d, ramp: %d", animProps.profileIndex, animProps.frontLight.minDuty, animProps.frontLight.maxDuty, animProps.frontLight.holdTime, animProps.frontLight.rampTime); - Buzzer_Beep(150, 3000); - } - }else{ - ESP_LOGE(tag, "Deserialization error for wifi.json"); - } - - getpostSuccess = true; - //goto done; - } - else if(!strncmp(dataType, "anim-profile", 12)){ - if (strlen(dataType) > 12) { - int profile_index = (dataType[12] - '0' - 1) % 8; // extract index, assuming dataType has enough characters - JsonDocument profJson; - DeserializationError error = deserializeJson(profJson, postData); - - if(!error){ - JsonArray eventsArray = profJson["events"]; - for(int i = 0; i < eventsArray.size(); i++ ){ - animProps.event[i].selfIndex = i; - animProps.event[i].animIndex = eventsArray[i]["anim"].as(); - animProps.event[i].hue = eventsArray[i]["hue"].as(); - animProps.event[i].hueRange = eventsArray[i]["hue-range"].as(); - animProps.event[i].speed = eventsArray[i]["speed"].as(); - animProps.event[i].param1 = eventsArray[i]["param1"].as(); - animProps.event[i].param2 = eventsArray[i]["param2"].as(); - animProps.event[i].check1 = eventsArray[i]["check1"].as(); - animProps.event[i].check2 = eventsArray[i]["check2"].as(); - animProps.event[i].check3 = eventsArray[i]["check3"].as(); - animProps.event[i].check4 = eventsArray[i]["check4"].as(); - animProps.event[i].countDown = 0; - } - - ESP_LOGD(tag, "Extracted/Updated active profile to animProps."); - - // Save to disk/flash - String filePath = "/cfg/anim-profile" + String(profile_index + 1) + ".json"; - if(updateJsonDocument(profJson, filePath.c_str())){ - Buzzer_Beep(150, 3000); - } - - }else{ - ESP_LOGE(tag, "Deserialization error for wifi.json"); - } - - getpostSuccess = true; - } - } - else if(!strcmp(dataType, "play-anim")){ - JsonDocument animData; - DeserializationError error = deserializeJson(animData, postData); - if(!error){ - ANIMATION_EVENT testEvent; - testEvent.selfIndex = animData["index"].as(); - testEvent.animIndex = animData["anim"].as(); - testEvent.hue = animData["hue"].as(); - testEvent.hueRange = animData["hue-range"].as(); - testEvent.speed = animData["speed"].as(); - testEvent.param1 = animData["param1"].as(); - testEvent.param2 = animData["param2"].as(); - testEvent.check1 = animData["check1"].as(); - testEvent.check2 = animData["check2"].as(); - testEvent.check3 = animData["check3"].as(); - testEvent.check4 = animData["check4"].as(); - - if(testEvent.selfIndex != 0){ - testEvent.selfIndex = 1; - } - ESP_LOGI(tag, "Post:play-anim, index: %d, anim: %d, hue: %d, rng: %d, speed: %d, par1: %d, par2: %d, chk1: %d, chk2: %d, chk3: %d, chk4: %d", testEvent.selfIndex, testEvent.animIndex, testEvent.hue, testEvent.hueRange, testEvent.speed, testEvent.param1, testEvent.param2, testEvent.check1, testEvent.check2, testEvent.check3, testEvent.check4); - testEvent.countDown = 0; // set to zero so param1 determines countdown time - testEvent.type = EV_TEST; - PostNewEvent(testEvent); // eventIndex always = 1 - Buzzer_Beep(150, 3000); - }else{ - ESP_LOGE(tag, "Deserialization error for play-anim"); - } - - getpostSuccess = true; - } - else if(!strcmp(dataType, "wifi")){ - JsonDocument wifiCreds; - DeserializationError error = deserializeJson(wifiCreds, postData, total); - if(!error){ - //read credentials - //const char* new_ssid = wifiCreds["ssid"]; - //const char* new_pass = wifiCreds["pass"]; - - String new_ssid = wifiCreds["ssid"]; - String new_pass = wifiCreds["pass"]; - ESP_LOGV(tag, "SSID: %s PASS: %s", new_ssid, new_pass); - // Save Credentials if different - //if(strcmp(new_ssid, ssid)!=0 || strcmp(new_pass, passPhrase)!=0){ - if(new_ssid != ssid || new_pass != passPhrase){ - Wifi_Save_Credentials(new_ssid, new_pass); - StartDelayedRebooth; - } - }else{ - ESP_LOGE(tag, "Deserialization error for wifi"); - } - - getpostSuccess = true; - } - else if(!strcmp(dataType, "set-pixel")){ - JsonDocument js; - DeserializationError error = deserializeJson(js, postData); - if(!error){ - ANIMATION_EVENT testEvent; - testEvent.selfIndex = 1; - testEvent.animIndex = 81; - testEvent.hue = js["hue"].as(); - testEvent.param1 = js["index"].as(); - testEvent.type = EV_TEST; - PostNewEvent(testEvent); // eventIndex always = 1 - ESP_LOGD(tag, "Post: set-pixel, hue: %d, pixel: %d", testEvent.hue, testEvent.param1); - Buzzer_Beep(150, 3000); - }else{ - ESP_LOGE(tag, "Deserialization error for set-pixel"); - } - - Buzzer_Beep(50, 3000); - getpostSuccess = true; - } - else if(!strcmp(dataType, "clear-strip")){ - ANIMATION_EVENT testEvent; - testEvent.selfIndex = 1; - testEvent.animIndex = 80; - ESP_LOGD(tag, "Post: clear-strip"); - testEvent.type = EV_TEST; - PostNewEvent(testEvent); // eventIndex always = 1 - - getpostSuccess = true; - Buzzer_Beep(50, 3000); - } - else if(!strcmp(dataType, "setup-save")){ - JsonDocument js; - DeserializationError error = deserializeJson(js, postData); - if(!error){ - // If app index is different open app-events.json and update - if(sysProps.appIndex != js["appindex"].as()){ - File file = LittleFS.open("/cfg/app-events.json", "r+"); - if(!file){ - ESP_LOGE(tag, "Failed to open app-events.json"); - file.close(); - return; - } - - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - - if(!error){ - // Update index value - doc["index"] = js["appindex"].as(); - ESP_LOGD(tag, "New App Index = %d", doc["index"].as()); - - if(updateJsonDocument(doc, "/cfg/app-events.json")){ - Buzzer_Beep(150, 3000); - } - }else{ - ESP_LOGE(tag, "Deserialization error for app-events.json"); - } - } - }else{ - ESP_LOGE(tag, "Deserialization error for seteup-save"); - } - - // if any of the values are diiferent then open led-devices.json and update - //if app index is different open app-events.json and update - bool editJson = false; - //if(js["en1"].as() != strip1->size) { editJson = true; } - if(js["count1"].as() != strip1->size) { editJson = true; } - else if(js["shift1"].as() != strip1->shift) { editJson = true; } - else if(js["offset1"].as() != strip1->offset) { editJson = true; } - else if(js["rgb1"].as() != strip1->ledOrder) { editJson = true; } - else if(js["power1"].as() != strip1->powerDiv) { editJson = true; } - - if(editJson){ - File file = LittleFS.open("/cfg/led-devices.json", "r+"); - if(!file){ - ESP_LOGE(tag, "Failed to open led-devices.json"); - file.close(); - return; - } - - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - - if(!error){ - JsonObject jsStrip1 = doc["strip1"].to(); // nested so it doesn't create a copy - - jsStrip1["en"] = true; - jsStrip1["size"] = js["count1"].as(); - jsStrip1["shift"] = js["shift1"].as(); - jsStrip1["offset"] = js["offset1"].as(); - jsStrip1["power-div"] = js["power1"].as(); - jsStrip1["rgb-order"] = js["rgb1"]; - - // Save Json File - if(updateJsonDocument(doc, "/cfg/led-devices.json")){ - Buzzer_Beep(150, 3000); - } - }else{ - ESP_LOGE(tag, "Deserialization error for led-devices.json"); - } - } - - ESP_LOGD(tag, "Post: setup-save"); - getpostSuccess = true; - Buzzer_Beep(150, 3000); - } - else if(!strcmp(dataType, "restart")){ - StartDelayedRebooth; - - ESP_LOGD(tag, "Post: restart"); - getpostSuccess = true; - Buzzer_Beep(150, 3000); - } - } - - // Delete the allocated buffer (owned by the request->_tempObject) - delete[] postData; - } -} - -bool isInternetConnected() -{ - if (WiFi.status() == WL_CONNECTED) { // check if WiFi is connected - WiFiClient client; - const int httpPort = 80; - if (client.connect("www.google.com", httpPort)) { // try to connect to Google - client.stop(); - return true; // Internet access available - } - } - return false; // Internet access not available -} - -void handlePOST_Upload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) -{ - if (!index && request->hasParam("dir-path", true, false)) { - AsyncWebParameter* p = request->getParam("dir-path",true, false); - String path = p->value() + "/" + filename; - ESP_LOGD(tag, "upload path: %s", path.c_str()); - - request->_tempFile= LittleFS.open(path, "w"); - //fs::File file = LittleFS.open(path, "w"); - if (!request->_tempFile) { - ESP_LOGE(tag, "Failed to create file!"); - return; - } - - }else{ - ESP_LOGE(tag, "dir-path Param not found.."); - } - - if(len && request->_tempFile){ - request->_tempFile.write(data, len); - } - - if(final){ - request->_tempFile.close(); - request->redirect("/files"); - ESP_LOGD(tag, "UploadEnd: %s, %u B", filename.c_str(), index+len); - } -} - -void handleGET_DSLRBooth(AsyncWebServerRequest *request) -{ - static int lastCountdown = 1000; - request->send(200, "text/plain"); // send this right away to avoid comm delays - - if(request->args() >= 1){ - int x = 0; - const char* event_type = request->arg( x ).c_str(); - - if(strcmp("countdown", event_type) == 0){ - int p = request->arg(1).toInt(); - if(p > 0 && p <= 100){ - animStatus.countStatus = p; - } - - // in case "coundown_start" was missed - if(animStatus.EventsIndex != ANIM_WHITEFILL_INDEX){ - animProps.event[0].countDown = lastCountdown; - animProps.event[0].type = EV_NORMAL; - PostNewEvent(animProps.event[0]); - } - } - else if(strcmp("countdown_start", event_type) == 0){ // index=0 - int count = request->arg(1).toInt(); // retrieve countdown value - //Log.traceln(" countdown = %d", count); - if(count < 1){count = 1;} - count *= 1000; - lastCountdown = count - 500; - animProps.event[0].countDown = lastCountdown; - animProps.event[0].type = EV_NORMAL; - PostNewEvent(animProps.event[0]); - } - else if(strcmp("sharing_screen", event_type) == 0){ - animProps.event[2].type = EV_NORMAL; - PostNewEvent(animProps.event[2]); - } - else if(strcmp("session_end", event_type) == 0){ //index=1 - animProps.event[1].type = EV_NORMAL; - PostNewEvent(animProps.event[1]); - } - else{ - // else if(strcmp_P("session_start", event_type) == 0){ - // TODO determine if ramp down is active depending on session type - - /* - const char* param1 = request->arg(1).c_str(); - if(strcmp("PrintOnly", param1)){ - animStatus.Animation = ANIM_START_PRINTONLY; - xTaskNotifyGive( Strip1_Task_Handle ); - //Serial.println("ses_print..\n\r"); - }else if(strcmp("PrintAndGIF", param1)){ - animStatus.Animation = ANIM_START_PRINTGIF; - xTaskNotifyGive( Strip1_Task_Handle ); - //Serial.println("ses_prnt_gif..\n\r"); - }else if(strcmp("OnlyGIF", param1)){ - animStatus.Animation = ANIM_START_GIFONLY; - xTaskNotifyGive( Strip1_Task_Handle ); - //Serial.println("ses_gif..\n\r"); - }else if(strcmp("Boomerang", param1)){ - animStatus.Animation = ANIM_START_BOOM; - xTaskNotifyGive( Strip1_Task_Handle ); - //Serial.println("ses_boom..\n\r"); - }else if(strcmp("Video", param1)){ - animStatus.Animation = ANIM_START_VIDEO; - xTaskNotifyGive( Strip1_Task_Handle ); - //Serial.println("ses_vid..\n\r"); - } - */ - } - } -} - -bool isFirmware = true; -bool updateSuccessful = false; -void handlePOST_Update(AsyncWebServerRequest *request) -{ - bool hasError = Update.hasError(); - String responseContent = hasError ? "failed" : "success"; - String responseType = hasError ? "text/plain" : "text/html"; - int responseCode = hasError ? 500 : 200; - - AsyncWebServerResponse *response = request->beginResponse(responseCode, responseType, responseContent); - response->addHeader("status", responseContent); - request->send(response); -} - -// handlePOST_Update Callback function to install the firmware or file system bin files -void updateCallback(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) -{ - // Do Once Code - if (!index) { - size_t fileSize = UPDATE_SIZE_UNKNOWN; - // Retrieve file-size parameter - if(request->hasParam("file-size", true, false)) { // make sure param is from POST request or it will not find it - fileSize = request->getParam("file-size", true, false)->value().toInt(); - } - - // register progress callback function - Update.onProgress(updateFirmwareProgress); - updateSuccessful = false; - - //file name checks - if (filename.startsWith("ata_fw")) { - isFirmware = true; - if (!Update.begin(fileSize, U_FLASH, BoardLED2)) { - ESP_LOGD(tag, "Firmware update failed to start"); - return; - } - ESP_LOGD(tag, "Updating Firmware with: %s Size:%d ", filename.c_str(), fileSize); - } - else if (filename.startsWith("ata_fs")) { - isFirmware = false; - if (!Update.begin(fileSize, U_SPIFFS, BoardLED2)) { - ESP_LOGD(tag, "LittleFS update failed to start"); - return; - } - ESP_LOGD(tag, "Updating File System with: %s Size:%d ", filename.c_str(), fileSize); - } - else { - ESP_LOGD(tag, "Unsupported file type"); - return; - } - } - - // Writing... - if (!Update.hasError()) { - if (Update.write(data, len) != len) { - Update.printError(Serial); - } - } - - // All Done... - if (final) { - vTaskDelay(100); - if(isFirmware) { // firmware update - if (Update.end(true)) { - RebootSystem = true; - updateSuccessful = true; - ESP_LOGD(tag, "firmware update successful: %d", index + len); - } - else { - Update.printError(Serial); - } - } - else{ // file system update - if(Update.end(true)) { - updateSuccessful = true; - ESP_LOGD(tag, "file system update successful!"); - } - else { - Update.printError(Serial); - } - } - } -} - -// Server requested files that aren't template processed -void handleGET_SendFile(AsyncWebServerRequest *request)// try this later "^/(img|favicon).*" -{ - String filePath = request->url(); - const char* ext = getFileExtension(filePath.c_str()); - const char* contentType = getFileType(ext); - - if( contentType == NULL ){ - request->send(404); - return; - } - - if(filePath.c_str()[0] != '/'){ - filePath = '/' + filePath; - } - - if (!strcmp(ext,"html") || !strcmp(ext, "htm") || !strcmp(ext, "css") || !strcmp(ext, "js")) { - if(!filePath.startsWith("/www/")){ - filePath = "/www" + filePath; - } - } - - ESP_LOGD(tag, "Sent: %s", filePath.c_str()); - request->send(LittleFS, filePath, contentType); -} - -String listDir(String directoryList[], int count) -{ - String listedFiles; - - for (int i = 0; i < count; i++) { - // directory html - listedFiles += "Dir: "; - listedFiles += directoryList[i]; - listedFiles += "/-\n"; - - filesDropdownOptions += "\n"; - - dirDropdownOptions += "\n"; - - File dir = LittleFS.open(directoryList[i]); - File file = dir.openNextFile(); - while (file) { - String fileName = file.name(); - if (!file.isDirectory()) { - //Serial.println(" File: " + String(file.name())); - listedFiles += "  "; - listedFiles += fileName; - listedFiles += ""; - listedFiles += convertFileSize(file.size()); - listedFiles += "\n"; - - filesDropdownOptions += "\n"; - } - file = dir.openNextFile(); - } - dir.close(); - } - - return listedFiles; -} - -char* readFile(fs::FS &fs, const char* path) { - File file = fs.open(path, "r"); - if (!file || file.isDirectory()) { - return nullptr; - } - - size_t fileSize = file.size(); - char* fileContent = new char[fileSize + 1]; // +1 for null-terminator - - size_t bytesRead = file.readBytes(fileContent, fileSize); - file.close(); - - fileContent[bytesRead] = '\0'; // Set null-terminating character - - if (bytesRead != fileSize) { - delete[] fileContent; - return nullptr; - } - - return fileContent; -} - -void writeFile(fs::FS &fs, const char * path, const char * message) -{ - File file = fs.open(path, "w"); - if(!file){ - return; - } - file.print(message); - file.close(); -} - -// Send html file with template processing {{VAR}} -void sendHtmlFile(const char* filePath, AsyncWebServerRequest *request, String (*callback)(const String&)) -{ - ESP_LOGD(tag, "Sent file: %s", filePath); - File file = LittleFS.open(filePath, "r"); - const char* htmlFile = readFile(LittleFS, filePath); - - //String processedData = varReplace(htmlFile, htmlProcessor); - String processedData = varReplace(htmlFile, callback); - request->send(200, "text/html", processedData); -} - -const char* convertFileSize(const size_t bytes) { - static char fileSizeBuffer[16]; // PreAllocated buffer for the file size - - if (bytes < 1024) { - snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%d B", bytes); - } else if (bytes < 1024*1024) { - snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%.2f kB", static_cast(bytes) / 1024.0); - } else if (bytes < 1024*1024*1024) { - snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%.2f MB", static_cast(bytes) / 1048576.0); - } else { - fileSizeBuffer[0] = '\0'; // Empty string if the file size is too large - } - - return fileSizeBuffer; -} - -// Callback template processor -String htmlProcessor(const String& var) -{ - if(var == "NAVBAR"){ return String("\n"); } - - if(var == "ALLOWED_EXTENSIONS_EDIT"){ return allowedExtensionsForEdit; } - - if(var == "FS_FREE_BYTES"){ return convertFileSize(LittleFS.totalBytes() - LittleFS.usedBytes()); } - - if(var == "FS_USED_BYTES"){ return convertFileSize(LittleFS.usedBytes()); } - - if(var == "FS_TOTAL_BYTES"){ return convertFileSize(LittleFS.totalBytes()); } - - if(var == "LISTED_FILES"){ - filesDropdownOptions = ""; // clear out - dirDropdownOptions = ""; // clear out - String directories[8]; - int dirCount = 0; - getAllDirectories(directories, dirCount); - - return listDir(directories, dirCount); - } - - if(var == "EDIT-DEL_FILES"){ return filesDropdownOptions; } - - if(var == "DIR_LIST"){ return dirDropdownOptions; } - - if(var == "SAVE_PATH_INPUT"){ - if(savePath == "/new.txt"){ - return String(""; - } - else{ - return String(""; - } - } - - if(var == "FIRM_VER"){ return FIRMWARE_VER; } - - return var; -} - -String HomeHtmlProcessor(const String& var) { - if(var == "NAVBAR"){ return String("\n"); } - - if (var == "APP_NAME") { - return sysProps.appName; - } - if (var == "OLED") { - return "No"; - } - if (var == "STRIP1") { - return (strip1) ? "Yes" : "No"; - } - if (var == "STRIP2") { - return (strip2) ? "Yes" : "No"; - } - if (var == "FRONT_LIGHT") { - return (animProps.frontLight.enabled) ? "Yes" : "No"; - } - if (var == "REAR_LIGHT") { - return (animProps.rearLight.enabled) ? "Yes" : "No"; - } - if (var == "FIRMWARE") { - return FIRMWARE_VER; - } - if (var == "BOOTH_T") { - return String(sysProps.t_sensor.temperature) + "F"; - } - if (var == "SETPOINT") { - return String(sysProps.t_sensor.Setpoint1) + "F"; - } - if (var == "FLASH_SIZE") { - return convertFileSize(ESP.getSketchSize()); - } - if (var == "FLASH_FREE") { - return convertFileSize(ESP.getFreeSketchSpace()); - } - if (var == "HEAP_SIZE") { - return convertFileSize(ESP.getHeapSize()); - } - if (var == "HEAP_FREE") { - return convertFileSize(ESP.getFreeHeap()); - } - if (var == "CPU_FREQ") { - return String(ESP.getCpuFreqMHz()) + "Mhz"; - } - if (var == "IP") { - return WiFi.localIP().toString(); - } - if (var == "MAC") { - return chipInfo.macStr; - } - if (var == "SSID") { - return WiFi.SSID(); - } - if (var == "RSSI") { - return String(WiFi.RSSI()); - } - if (var == "WIFI_CH") { - return String(WiFi.channel()); - } - if (var == "ENCRYP") { - return String(WiFi.encryptionType(0)); - } - if (var == "AP_SSID") { - return WiFi.softAPSSID(); - } - if (var == "AP_CLIENTS") { - return String(WiFi.softAPgetStationNum()); - } - if (var == "BLE") { - return (commMode == COMM_WIFI_AP_BLE) ? "Yes" : "No"; - } - if (var == "BLE_SSID") { - return (commMode == COMM_WIFI_AP_BLE) ? BLEDeviceName : ""; - } - if (var == "BLE_CLIENTS") { - return (BTDeviceConnected) ? "1" : "0"; - } - if (var == "AP_MAC") { - return getSoftAPMacAddress(); - } - - - // Return an empty string if the variable is not recognized - return var; -} - -String getSoftAPMacAddress() { - uint8_t mac[6]; - WiFi.softAPmacAddress(mac); - - String macString = ""; - for (int i = 0; i < 6; i++) { - macString += String(mac[i], HEX); - if (i < 5) macString += ":"; - } - return macString; -} - -// Finds segments between {{VAR}} and calls a callback function to replace VAR with new content -String varReplace(const String& input, String (*callback)(const String&)) { - if (input.isEmpty()) { - return input; - } - - String result; - int startPos = 0; - int start = input.indexOf("{{", startPos); - - while (start != -1) { - result += input.substring(startPos, start); - - int end = input.indexOf("}}", start + 2); - if (end == -1) { - break; - } - - String segment = input.substring(start + 2, end); - int segmentLength = segment.length(); - if (segmentLength <= 32) { - String replacement = callback(segment); - result += replacement; - } else { - result += input.substring(start, end + 2); // Include the original segment if it exceeds the limit - } - - startPos = end + 2; - start = input.indexOf("{{", startPos); - } - - result += input.substring(startPos); - return result; -} - -const char* getFileExtension(const char* filename) { - size_t dotPos = strlen(filename); - while (dotPos > 0 && filename[dotPos - 1] != '.') { - dotPos--; - } - - if (dotPos != 0 && dotPos < strlen(filename) - 1) { - return &filename[dotPos]; - } - - return ""; // Empty string if no extension found -} - -const char* getFileType(const char* ext) { - if (strcmp(ext, "png") == 0) { - return "image/png"; - } else if (strcmp(ext, "jpg") == 0 || strcmp(ext, "jpeg") == 0) { - return "image/jpeg"; - } else if (strcmp(ext, "gif") == 0) { - return "image/gif"; - } else if (strcmp(ext, "ico") == 0) { - return "image/x-icon"; - } else if (strcmp(ext, "txt") == 0) { - return "text/plain"; - } else if (strcmp(ext, "css") == 0) { - return "text/css"; - } else if (strcmp(ext, "htm") == 0 || strcmp(ext, "html") == 0) { - return "text/html"; - } else if (strcmp(ext, "js") == 0) { - return "text/javascript"; - } else if (strcmp(ext, "json") == 0) { - return "application/json"; - } else { - return ""; - } -} - -// Serial print firmware or file system update progress -void updateFirmwareProgress(size_t progress, size_t total) -{ - static int lastProg = -1; - int firmwareProgress = (progress * 100)/ total; - - if(firmwareProgress != lastProg){ - Serial.printf("Progress: %u%%\r", firmwareProgress); - lastProg = firmwareProgress; - //TODO Add buzzer tune while uploading firmware - //Buzzer_Play_Tune(TUNE_DOWNLOADING,1,true,false); - } -} - - diff --git a/temporary/Temp/my_wifi.h b/temporary/Temp/my_wifi.h deleted file mode 100644 index 67f0773..0000000 --- a/temporary/Temp/my_wifi.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef _MY_WIFI_H -#define _MY_WIFI_H - -#include -#include -#include - -extern int RebootSystem; - -void Wifi_Start_WebServer(void); -void Init_Wifi_Task(void); -void Wifi_Start_MDNS(void); -void Wifi_Task(void *parameters); -String getSoftAPMacAddress(void); -//void onWiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info); -void onWiFiEvent(WiFiEvent_t event); -void Wifi_Request_Task(void *parameters); -void Setup_WebServer_Handlers(AsyncWebServer* serv); - -void Wifi_Read_Credentials(const JsonObject &credJson); -void Wifi_Save_Credentials(String newSSID, String newPass); -bool isInternetConnected(void); -void Wifi_Client_Loop(void); - -// Handlers -void handlePOST_RegStick(AsyncWebServerRequest *request); - -void handleGET_DSLRBooth(AsyncWebServerRequest *request); -void handlePOST_Upload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); -void handlePOST_Update(AsyncWebServerRequest *request); -void updateCallback(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); -void updateFirmwareProgress(size_t progress, size_t total); - -void handleGET_SendFile(AsyncWebServerRequest *request); -void onFileUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); - -void handleGET_Get(AsyncWebServerRequest *request); -void handlePOST_Post(AsyncWebServerRequest *request); -void postFileUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final); -void postBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total); - - -void sendHtmlFile(const char* filePath, AsyncWebServerRequest *request, String (*callback)(const String&)); -String htmlProcessor(const String& var); -String HomeHtmlProcessor(const String& var); -//const char* htmlProcessor(const char* var); -String listDir(fs::FS &fs, const char *dirname, bool isSubdirectory); - -const char* getFileExtension(const char* filename); -const char* getFileType(const char* ext); -const char* convertFileSize(const size_t bytes); -char* readFile(fs::FS &fs, const char* path); -void writeFile(fs::FS &fs, const char * path, const char * message); - -String varReplace(const String& input, String (*callback)(const String&)); -//const char* varReplace(const char* input, const char* (*callback)(const char*)); - -void CreateSysSummmaryPacket(JsonDocument &doc); - - - - - - - -#endif \ No newline at end of file diff --git a/temporary/Temp/neo_colors.h b/temporary/Temp/neo_colors.h deleted file mode 100644 index 0ffaf31..0000000 --- a/temporary/Temp/neo_colors.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef NEO_COLORS_H -#define NEO_COLORS_H - -#include - -#define USE_CORRECTED_COLORS 0 - -const RgbColor col_black(0, 0, 0); -const RgbColor col_white(255, 255, 255); -const RgbColor col_red(255, 0, 0); -const RgbColor col_green(0, 255, 0); -const RgbColor col_blue(0, 0, 255); - -#if USE_CORRECTED_COLORS == 0 - -const RgbColor col_orange(255, 165, 0); -const RgbColor col_yellow(255, 255, 0); -const RgbColor col_cyan(0, 255, 255); -const RgbColor col_magenta(255, 0, 255); -const RgbColor col_purple(128, 0, 128); -const RgbColor col_pink(255, 192, 203); -const RgbColor col_teal(0, 128, 128); -const RgbColor col_lime(0, 255, 0); -const RgbColor col_indigo(75, 0, 130); -const RgbColor col_maroon(128, 0, 0); -const RgbColor col_navy(0, 0, 128); -const RgbColor col_olive(128, 128, 0); -const RgbColor col_beige(245, 245, 220); -const RgbColor col_brown(165, 42, 42); -const RgbColor col_coral(255, 127, 80); -const RgbColor col_gold(255, 215, 0); -const RgbColor col_gray(128, 128, 128); -const RgbColor col_ivory(255, 255, 240); -const RgbColor col_khaki(240, 230, 140); -const RgbColor col_lavender(230, 230, 250); -const RgbColor col_peach(255, 218, 185); -const RgbColor col_periwinkle(204, 204, 255); -const RgbColor col_salmon(250, 128, 114); -const RgbColor col_sienna(160, 82, 45); -const RgbColor col_silver(192, 192, 192); -const RgbColor col_tan(210, 180, 140); -const RgbColor col_turquoise(64, 224, 208); -const RgbColor col_violet(238, 130, 238); - -#else - -const RgbColor col_orange(255, 128, 0); -const RgbColor col_yellow(255, 255, 0); -const RgbColor col_cyan(0, 255, 255); -const RgbColor col_magenta(255, 0, 255); -const RgbColor col_purple(170, 0, 255); -const RgbColor col_pink(255, 170, 255); -const RgbColor col_teal(0, 128, 128); -const RgbColor col_lime(128, 255, 0); -const RgbColor col_indigo(85, 0, 255); -const RgbColor col_maroon(128, 0, 0); -const RgbColor col_navy(0, 0, 128); -const RgbColor col_olive(128, 128, 0); -const RgbColor col_beige(255, 230, 204); -const RgbColor col_brown(153, 51, 0); -const RgbColor col_coral(255, 102, 102); -const RgbColor col_gold(204, 153, 0); -const RgbColor col_gray(128, 128, 128); -const RgbColor col_ivory(255, 255, 204); -const RgbColor col_khaki(204, 204, 0); -const RgbColor col_lavender(204, 153, 255); -const RgbColor col_peach(255, 204, 153); -const RgbColor col_periwinkle(153, 153, 255); -const RgbColor col_salmon(255, 153, 102); -const RgbColor col_sienna(153, 76, 0); -const RgbColor col_silver(204, 204, 204); -const RgbColor col_tan(204, 153, 102); -const RgbColor col_turquoise(0, 204, 204); -const RgbColor col_violet(204, 0, 255); - -#endif - -#endif \ No newline at end of file diff --git a/temporary/Temp/otaupdate.cpp b/temporary/Temp/otaupdate.cpp deleted file mode 100644 index e18a99c..0000000 --- a/temporary/Temp/otaupdate.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "otaupdate.h" -#include "LittleFS.h" -#include -#include -#include "githubCert.h" -#include - - -String binFile = "manifest.json"; -String rootUrl = "https://raw.githubusercontent.com/ataindustries/atacontrolboardV1/main/"; -String github_token = "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"; - -const float FirmwareVer = 1.0; - -JsonDocument doc; - -int otaupdate_check(void) -{/* - String payload; - int httpCode; - WiFiClientSecure * client = new WiFiClientSecure; - HTTPClient https; - - String manifest_url = rootUrl + binFile + "?token=" + github_token; - https.begin(manifest_url); - httpCode = https.GET(); - - if (httpCode == HTTP_CODE_OK) // if version received - { - String payload = https.getString(); - JsonDocument doc; - deserializeJson(doc, payload); - - float firmver = doc["firmver"].as(); - const char* firmfile = doc["firmfile"]; - const char* fsfile = doc["fsfile"]; - - Serial.printf("From manifest: %.1f, %s, $s\n\r", firmver, firmfile, fsfile); - - if(firmver > FirmwareVer){ - Serial.println("New firmware available!"); - return 1; - }else{ - Serial.println("firmware is upto date!"); - return 0; - } - } - */ - return 0; -} - -void otaupdate_perform(void) -{ - - // setup events - ota_events(); - - - // Pause unnecessary tasks - - //check for update -} - -void ota_events(void) -{ - /* - fota->setUpdateEndCb( [](int partition) - { - //Serial.printf("Update could not finish with %s partition\n", partition==U_SPIFFS ? "spiffs" : "firmware" ); - }); - - fota->setProgressCb( [](size_t progress, size_t size) - { - //if( progress == size || progress == 0 ) Serial.println(); - //Serial.print("."); - }); - - fota->setUpdateCheckFailCb( [](int partition, int error_code) - { - //Serial.printf("Update could validate %s partition (error %d)\n", partition==U_SPIFFS ? "spiffs" : "firmware", error_code ); - // error codes: - // -1 : partition not found - // -2 : validation (signature check) failed - }); - - fota->setUpdateFinishedCb( [](int partition, bool restart_after) - { - //Serial.printf("Update could not begin with %s partition\n", partition==U_SPIFFS ? "spiffs" : "firmware" ); - - if( restart_after ) { - ESP.restart(); - } - }); - */ -} - diff --git a/temporary/Temp/otaupdate.h b/temporary/Temp/otaupdate.h deleted file mode 100644 index 0667dea..0000000 --- a/temporary/Temp/otaupdate.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _OTAUPDATE_H -#define _OTAUPDATE_H - -#include - - -int otaupdate_check(float myVer); - -void otaupdate_perform(String filePath); - -void ota_events(void); - - -#endif \ No newline at end of file diff --git a/temporary/Temp/rf_transceiver.cpp b/temporary/Temp/rf_transceiver.cpp deleted file mode 100644 index 1ff5e67..0000000 --- a/temporary/Temp/rf_transceiver.cpp +++ /dev/null @@ -1,44 +0,0 @@ - -#include "rf_transceiver.h" - -static const char* tag = "trx433"; -TaskHandle_t RF_Task_Handle; - -const int txChannel = RMT_CHANNEL_0; -const int rxChannel = RMT_CHANNEL_1; - -void Init_RF_Receiver(void) -{ - /* - // Configure RMT receiver - rmt_config_t rxConfig; - rxConfig.channel = (rmt_channel_t)rxChannel; - rxConfig.gpio_num = static_cast(RMT_RX_PIN); - // Set other reception settings as needed - rmt_config(&rxConfig); - rmt_driver_install(rxConfig.channel, 1000, 0); - - xTaskCreatePinnedToCore(RF_Control_Task, "RF_Task", 8000, NULL, 1, &RF_Task_Handle, 0); - */ -} - -void Init_RF_Transmitter(void) -{ - /* - rmt_config_t txConfig; - txConfig.channel = (rmt_channel_t)txChannel; - txConfig.gpio_num = static_cast(RMT_TX_PIN); - // Set other transmission settings as needed - rmt_config(&txConfig); - rmt_driver_install(txConfig.channel, 0, 0); - */ -} - -void RF_Control_Task(void *parameters) -{ - for(;;){ - vTaskDelay(100); - } -} - - diff --git a/temporary/Temp/rf_transceiver.h b/temporary/Temp/rf_transceiver.h deleted file mode 100644 index 091368f..0000000 --- a/temporary/Temp/rf_transceiver.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _RF_TRANSCEIVER_H -#define _RF_TRANSCEIVER_H - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" - -#include -#include -#include "my_board.h" - -#define RMT_RX_PIN RX433_Pin -#define RMT_TX_PIN TX433_Pin -#define RTM_RX_CHANNEL 0 -#define RTM_TX_CHANNEL 1 - -void Init_RF_Receiver(void); - -void Init_RF_Transmitter(void); - -void RF_Control_Task(void *parameters); - -#endif \ No newline at end of file diff --git a/temporary/Temp/styles.css b/temporary/Temp/styles.css deleted file mode 100644 index 94eac3f..0000000 --- a/temporary/Temp/styles.css +++ /dev/null @@ -1,50 +0,0 @@ -.blue { - color: blue; -} - -h1{ - color: yellow; -} - -body{ - color: red; -} - -.secTitleFont{ - color: white; - -} -.secTitle{ - min-width: none; - height: 25px; - width: auto; - padding: 2px; - margin: 2px; - display: flex; - justify-content: center; - align-items: center; - /*border: 3px solid black;*/ - color: rgb(56, 132, 255); - background-color: rgb(61, 118, 153); - font-family: Tahoma, Arial, sans-serif; - font-size: smaller; - font-weight: bold; - flex-direction: ; -} - -.secCntrls{ - height: 100px; - width: auto; - margin: 5px; - border: 1px solid rgb(255, 255, 255); - color: rgba(255, 255, 255, 0); - font-family: Tahoma, Arial, sans-serif; - /*display: flex; - justify-content: center; - align-items: center; - position: relative;*/ -} - -.dropList{ - margin-right: 40px; -} \ No newline at end of file diff --git a/temporary/Temp/update.json b/temporary/Temp/update.json deleted file mode 100644 index 007f91a..0000000 --- a/temporary/Temp/update.json +++ /dev/null @@ -1,190 +0,0 @@ -{ - "files": [ - { - "remote": "data/ata-boothifier-upgrade.html", - "local": "/ata-boothifier-upgrade.html", - "md5": "92074ec24fd467545272eb9e837d644c", - "size": 16980 - }, - { - "remote": "data/ata-boothifier-upgradeV2.html", - "local": "/ata-boothifier-upgradeV2.html", - "md5": "484648993370e4b6aff13124bd1c55c1", - "size": 18178 - }, - { - "remote": "data/ata-boothifier-upgradeV3.html", - "local": "/ata-boothifier-upgradeV3.html", - "md5": "79426145db379ac15ccc742245a31ecb", - "size": 17233 - }, - { - "remote": "data/favicon.ico", - "local": "/favicon.ico", - "md5": "ba4c4e3bf5e5db2bbfc56a52f3657d79", - "size": 1150 - }, - { - "remote": "data/flashstik-reg.html", - "local": "/flashstik-reg.html", - "md5": "394fdfe3cd3fb89a8ddb3d6edf2d2da4", - "size": 15651 - }, - { - "remote": "data/css/global-style.css", - "local": "/css/global-style.css", - "md5": "217a9cca8b4eae2d28fa8bc5a0f6db09", - "size": 1239 - }, - { - "remote": "data/css/nav.css", - "local": "/css/nav.css", - "md5": "e653a75433056f28e3f410f567b8622c", - "size": 1538 - }, - { - "remote": "data/images/atalogo.png", - "local": "/images/atalogo.png", - "md5": "5a18c88a4ea80c8d8d0ad52b2fdbbadc", - "size": 16690 - }, - { - "remote": "data/images/favicon-32x32.png", - "local": "/images/favicon-32x32.png", - "md5": "d80cf74ace3a8be487a5158bca48f9b6", - "size": 2428 - }, - { - "remote": "data/js/event-box.js", - "local": "/js/event-box.js", - "md5": "553f26707686038e275227a97eb96659", - "size": 12341 - }, - { - "remote": "data/js/fwUoload.js", - "local": "/js/fwUoload.js", - "md5": "d4a734cce529c3adf831ea46259f9c2d", - "size": 1524 - }, - { - "remote": "data/js/hue-select.js", - "local": "/js/hue-select.js", - "md5": "0a58f1a339af5c54aecfc5ce1aac7168", - "size": 6367 - }, - { - "remote": "data/js/jquery-3.7.1.js", - "local": "/js/jquery-3.7.1.js", - "md5": "fdb81281d3773a7462998fdddbe6f5bf", - "size": 196885 - }, - { - "remote": "data/system/ble.json", - "local": "/system/ble.json", - "md5": "faebefd5b50046a01d4a8aa27f8504d0", - "size": 307 - }, - { - "remote": "data/system/readme.txt", - "local": "/system/readme.txt", - "md5": "198c92a2cc06b3effce3b5ba313cc6a0", - "size": 86 - }, - { - "remote": "data/system/tunes.json", - "local": "/system/tunes.json", - "md5": "814999e88296bee179cef5d394f3f696", - "size": 1149 - }, - { - "remote": "data/system/update.json", - "local": "/system/update.json", - "md5": "01cc6a1935601085df49308cab646673", - "size": 156 - }, - { - "remote": "data/www/about.html", - "local": "/www/about.html", - "md5": "23f0c991c5c67e7eefe6c24aa50b59fb", - "size": 4222 - }, - { - "remote": "data/www/edit.html", - "local": "/www/edit.html", - "md5": "fed238dcf87d3797b08ed371330ea800", - "size": 5546 - }, - { - "remote": "data/www/edit_old.html", - "local": "/www/edit_old.html", - "md5": "9aafba533ac77352d30841cdc34db0c4", - "size": 4240 - }, - { - "remote": "data/www/failed.html", - "local": "/www/failed.html", - "md5": "a24025d56bef1cd2ed5375f6e8853dde", - "size": 828 - }, - { - "remote": "data/www/files.html", - "local": "/www/files.html", - "md5": "52d82d4d23b038929691cd0fb20e8ee0", - "size": 9369 - }, - { - "remote": "data/www/home.html", - "local": "/www/home.html", - "md5": "767fd73b733d8e37dc79252fcd20b610", - "size": 7822 - }, - { - "remote": "data/www/index.html", - "local": "/www/index.html", - "md5": "af690aaa4dec02691ffdb2765c837370", - "size": 806 - }, - { - "remote": "data/www/lights.html", - "local": "/www/lights.html", - "md5": "272f8dc423923bb5026837240f654efe", - "size": 19056 - }, - { - "remote": "data/www/navbar.html", - "local": "/www/navbar.html", - "md5": "89af40b990e297e41e116105b04b66ee", - "size": 533 - }, - { - "remote": "data/www/ok.html", - "local": "/www/ok.html", - "md5": "db42bd2ff52293c3b4d6ef62fb4e3a42", - "size": 865 - }, - { - "remote": "data/www/setup.html", - "local": "/www/setup.html", - "md5": "19e1f419844852800757ccd36bb7892a", - "size": 11349 - }, - { - "remote": "data/www/upgrade.html", - "local": "/www/upgrade.html", - "md5": "f4a3efb67be66b5214d905e605984c93", - "size": 9080 - }, - { - "remote": "data/www/wifi.html", - "local": "/www/wifi.html", - "md5": "c6e55946a02cb0ff28689dd10d265987", - "size": 5320 - } - ], - "firmware": { - "md5": "fcec6e659842cc0333880b701a3e2634", - "size": 1401712 - }, - "release_date": "2025-08-20", - "release_time": "08:53:05" -} \ No newline at end of file diff --git a/temporary/Temp/upgrade.html b/temporary/Temp/upgrade.html deleted file mode 100644 index 7afb28a..0000000 --- a/temporary/Temp/upgrade.html +++ /dev/null @@ -1,228 +0,0 @@ - - - - Firmware Update - - - - - - - - - -

Firmware Update

- -
-
- Local Update -
-
- -
-
- -
-
-
- -
-
-
- -
-
- Web Update -
- -
- -
- -
- -
-
- -
-
- Update Progress -
- - - -
-
-
- - - - \ No newline at end of file diff --git a/temporary/Temp/web_ble.html b/temporary/Temp/web_ble.html deleted file mode 100644 index b8309a0..0000000 --- a/temporary/Temp/web_ble.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - BLE Interaction - - - -

BLE Interaction

- - - - - - - - diff --git a/temporary/ata-boothifier-upgradeV3_old.html b/temporary/ata-boothifier-upgradeV3_old.html deleted file mode 100644 index db06713..0000000 --- a/temporary/ata-boothifier-upgradeV3_old.html +++ /dev/null @@ -1,533 +0,0 @@ - - - - - - ATA Firmware Update - - - - -

ATA Firmware Update

- - -
- - -
- -
- -
- - -
- -
- - -
- -
- - -
- -
- -
-
- -
- -
- -
- -
- -
- - -
- - -
- - - - -
- - -
-
- -
-

WiFi Connection

-
- - -
- - -
-
-
- -
-
- - - - diff --git a/temporary/bak/cfg/!instructions.txt b/temporary/bak/cfg/!instructions.txt deleted file mode 100644 index 1e97b38..0000000 --- a/temporary/bak/cfg/!instructions.txt +++ /dev/null @@ -1,13 +0,0 @@ - -Choose Control App: - 1) Open app-events.json - 2) Change index to corresponding app - a. 0=DSLRBooth, 1=...., 2=..... - -Front Constant Light: ( to enable the light) - 1) Open led-devices.json - 2) Change "front-light", "en" to true - -Rear Constant Light: - 1) Open led-devices.json - 2) Change "rear-light", "en" to true \ No newline at end of file diff --git a/temporary/bak/cfg/anim-list.json b/temporary/bak/cfg/anim-list.json deleted file mode 100644 index 51dbbc4..0000000 --- a/temporary/bak/cfg/anim-list.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "whitefills":[ - { - "name":"Bottom/Up Fill", - "speed":"Speed: ", - "hue-range":"", - "param1":"Time: ", - "param2":"Const Light Delay: ", - "check1":"", - "check2":"", - "check3":"", - "check4":"50% Lum" - } - ], - "animations":[ - { - "name":"Rainbow", - "speed":"Speed: ", - "hue-range":"", - "param1":"", - "param2":"", - "check1":"", - "check2":"", - "check3":"", - "check4":"50% Lum" - }, - { - "name":"Hue Spectrum", - "speed":"Speed: ", - "hue-range":"Hue Range: ", - "param1":"", - "param2":"", - "check1":"Dir Rev ", - "check2":"", - "check3":"", - "check4":"50% Lum" - }, - { - "name":"Color Pulse Cycle", - "speed":"Speed: ", - "hue-range":"Hue Range: ", - "param1":"", - "param2":"Colors: ", - "check1":"", - "check2":"", - "check3":"", - "check4":"50% Lum" - }, - { - "name":"Comets", - "speed":"Speed: ", - "hue-range":"Hue Range: ", - "param1":"Sectors: ", - "param2":"Colors: ", - "check1":"Mixed Colors ", - "check2":"Random Decay", - "check3":"Shorter Tail ", - "check4":"50% Lum" - }, - { - "name":"Dashes", - "speed":"Speed: ", - "hue-range":"Hue Range: ", - "param1":"Sectors: ", - "param2":"Colors: ", - "check1":"Mixed Colors ", - "check2":"Rotate ", - "check3":"", - "check4":"50% Lum" - }, - { - "name":"Snakes", - "speed":"Speed: ", - "hue-range":"Hue Range: ", - "param1":"Sectors: ", - "param2":"Colors: ", - "check1":"Mixed Colors ", - "check2":"Rotate ", - "check3":"", - "check4":"50% Lum" - }, - { - "name":"Sectors", - "speed":"Speed: ", - "hue-range":"Hue Range: ", - "param1":"Sectors: ", - "param2":"Colors: ", - "check1":"", - "check2":"Rotate ", - "check3":"", - "check4":"50% Lum" - }, - { - "name":"Fire", - "speed":"Speed: ", - "hue-range":"Run-time per: ", - "param1":"Cooling: ", - "param2":"Sparking: ", - "check1":"Cycle Colors ", - "check2":"", - "check3":"", - "check4":"50% Lum" - } - ] -} \ No newline at end of file diff --git a/temporary/bak/cfg/anim-profiles.json b/temporary/bak/cfg/anim-profiles.json deleted file mode 100644 index e50c0e4..0000000 --- a/temporary/bak/cfg/anim-profiles.json +++ /dev/null @@ -1,1203 +0,0 @@ -{ - "countdown": { - "min": 0, - "max": 98, - "hold": 1000, - "ramp": 500 - }, - "profile-index": 3, - "profiles": [ - { - "name": "Profile 1", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Profile 2", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Profile 3", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Profile 4", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 75, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 1, - "hue": 0, - "hue-range": 340, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 3, - "hue": 0, - "hue-range": 340, - "speed": 75, - "param1": 30, - "param2": 60, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 40, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Profile 5", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Profile 5", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Wedding 7", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Wedding 8", - "events": [ - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - } - ] -} \ No newline at end of file diff --git a/temporary/bak/cfg/anim-settings.json b/temporary/bak/cfg/anim-settings.json deleted file mode 100644 index 3889b0e..0000000 --- a/temporary/bak/cfg/anim-settings.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "twinkle":{ - "col1": "#000000", - "col2": "#000000", - "density": 1, - "speed": 25, - "pwr": 255 - }, - "Strobe":{ - "col1": "#000000", - "col2": "#000000", - "density": 1, - "speed": 25, - "pwr": 255 - }, - "Solid":{ - "col1": "#000000", - "col2": "#000000", - "density": 1, - "pwr": 255 - }, - "Fade":{ - "col1": "#000000", - "range": 128, - "speed": 25, - "pwr": 255 - }, - "HueSwirl":{ - "col1": "#000000", - "range": 128, - "speed": 25, - "pwr": 255 - }, - "Meteors":{ - "col1": "#000000", - "col2": "#000000", - "range": 1, - "density": 1, - "speed": 25, - "pwr": 255 - }, - "Dashes":{ - "col1": "#000000", - "col2": "#000000", - "col3": "#000000", - "segments": 1, - "density": 1, - "speed": 25, - "pwr": 255 - }, - "DashesRange":{ - "col1": "#000000", - "col2": "#000000", - "range": 128, - "segments": 1, - "density": 1, - "speed": 25, - "pwr": 255 - }, - "Fire":{ - "col1": "#000000", - "cool": 25, - "spark": 25, - "speed": 25, - "pwr": 255 - }, - "Rain":{ - "col1": "#000000", - "col2": "#000000", - "range": 128, - "density": 1, - "speed": 25, - "pwr": 255 - }, - "Stacking":{ - "col1": "#000000", - "col2": "#000000", - "range": 128, - "speed": 25, - "pwr": 255 - }, - "Snake":{ - "col1": "#000000", - "col2": "#000000", - "range": 128, - "speed": 25, - "pwr": 255 - }, - "Theater":{ - "col1": "#000000", - "col2": "#000000", - "range": 128, - "speed": 25, - "step": 20, - "pwr": 255 - } -} \ No newline at end of file diff --git a/temporary/bak/cfg/app-events.json b/temporary/bak/cfg/app-events.json deleted file mode 100644 index fa7b393..0000000 --- a/temporary/bak/cfg/app-events.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "index": 0, - "apps":[ - { - "name": "DSLR-Booth Configuration", - "events":[ - "White Fill / Countdown", - "Experience Selection", - "Select Sharing Screen", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ] - }, - { - "name": "FotoFliqs Configuration", - "events":[ - "White Fill / Countdown", - "Experience Selection", - "Preview", - "Notice!", - "Idle / Pause", - "Advertisement", - "Printing", - "Phone Input / QR Code / Apple Drop", - "", - "", - "", - "" - ] - }, - { - "name": "Touchpix Configuration", - "events":[ - "White Fill / Countdown", - "Experience Selection", - "Preview", - "Notice!", - "Idle / Pause", - "Advertisement", - "Printing", - "Phone Input / QR Code / Apple Drop", - "", - "", - "", - "" - ] - }, - { - "name": "FotoZap Configuration", - "events":[ - "White Fill / Countdown", - "Experience Selection", - "Select Sharing Screen", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ] - }, - { - "name": "Twineit Configuration", - "events":[ - "White Fill / Countdown", - "Experience Selection", - "Select Sharing Screen", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ] - } - ] -} \ No newline at end of file diff --git a/temporary/bak/cfg/ble.json b/temporary/bak/cfg/ble.json deleted file mode 100644 index 8cd73ca..0000000 --- a/temporary/bak/cfg/ble.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "en": "true", - "core": 1, - "device-name": "ATA_COMM", - "key": "123456", - "service-uuid": "6E400001-B5A3-F393-E0A9-E50E24DCCA9E", - "char-uuid-rx": "6E400002-B5A3-F393-E0A9-E50E24DCCA9E", - "char-uuid-tx": "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" -} \ No newline at end of file diff --git a/temporary/bak/cfg/buzzer.json b/temporary/bak/cfg/buzzer.json deleted file mode 100644 index fa2cffd..0000000 --- a/temporary/bak/cfg/buzzer.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "en":true, - "boot":{ - "cycles": 1, - "pause": 0, - "tune": "Boot:d=16,o=5,b=112:f,g,a,b,b#" - }, - "restart":{ - "cycles": 1, - "pause": 0, - "tune": "Restart:d=16,o=5,b=112:f,g,a,b,b#" - }, - "wifi-conn":{ - "cycles": 1, - "pause": 0, - "tune": "WifiConn:d=16,o=5,b=112:f,a#,c6,f,a#,c6,f,a#,c6,f,a#,c6,f,a#,c6,f,a#,c6" - }, - "wifi-disc":{ - "cycles": 1, - "pause": 0, - "tune": "WifiDisc:d=16,o=5,b=112:f,g,a,b,b#" - }, - "ble-conn":{ - "cycles": 1, - "pause":0, - "tune": "BleConn:d=16,o=5,b=112:f,g,a,b,b#" - }, - "ble-disc":{ - "cycles": 1, - "pause": 0, - "tune": "BleDisc:d=16,o=5,b=112:f,g,a,b,b#" - }, - "click":{ - "cycles": 1, - "pause": 0, - "tune": "Click:d=16,o=5,b=112:f,g,a,b,b#" - }, - "error":{ - "cycles": 1, - "pause": 0, - "tune": "Error:d=16,o=5,b=112:32p,f,g,a,b,b#" - }, - "success":{ - "cycles": 1, - "pause": 0, - "tune": "Success:d=16,o=5,b=112:f,g,a,b,b#" - }, - "download":{ - "cycles": 1, - "pause": 0, - "tune": "Download:d=16,o=5,b=112:f,g,a,b,b#" - }, - "waiting":{ - "cycles": 1, - "pause": 0, - "tune": "Waiting:d=16,o=5,b=112:b" - }, - "beep":{ - "cycles": 1, - "pause": 0, - "tune": "Beep:d=16,o=5,b=112:b" - }, - "test":{ - "cycles": 1, - "pause": 0, - "tune": "Test:d=16,o=5,b=112:f,g,a,b,b#" - }, - "ack":{ - "cycles": 1, - "pause": 0, - "tune": "Ack:d=16,o=5,b=112:b,b#" - } -} \ No newline at end of file diff --git a/temporary/bak/cfg/firmware.json b/temporary/bak/cfg/firmware.json deleted file mode 100644 index d691b5d..0000000 --- a/temporary/bak/cfg/firmware.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "firm-index": 0, - "firm-locations":[ - "http://mylocation1", - "http://mylocation2", - "http://mylocation3" - ] -} \ No newline at end of file diff --git a/temporary/bak/cfg/led-devices.json b/temporary/bak/cfg/led-devices.json deleted file mode 100644 index 2935910..0000000 --- a/temporary/bak/cfg/led-devices.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "strip1": { - "en": true, - "size": 138, - "chip": "SK6812", - "rgb-order": "rgb", - "shift":0, - "offset": 0, - "power-div": 0, - "pin": 3, - "i2s-ch": 0, - "core": 0 - }, - "strip2": { - "en": false, - "size": 20, - "chip": "SK6812", - "rgb-order": "grb", - "shift":0, - "offset": 0, - "power-div": 0, - "pin": 46, - "i2s-ch": 1, - "core": 0 - }, - "front-light": { - "en": true, - "relay": 0, - "core": 1, - "style": 0, - "delay": 0.75 - }, - "rear-light": { - "en": true, - "relay": 1, - "button": 2, - "min": 0, - "max": 100, - "ramp":3000, - "steps":8 - } -} \ No newline at end of file diff --git a/temporary/bak/cfg/luma-stiks.json b/temporary/bak/cfg/luma-stiks.json deleted file mode 100644 index 724076b..0000000 --- a/temporary/bak/cfg/luma-stiks.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "stiks":[ - { - "en": true, - "ssid": "lumastikXX", - "mac": 5 - }, - { - "en": true, - "ssid": "lumastikXX", - "mac": 6 - } - ] -} \ No newline at end of file diff --git a/temporary/bak/cfg/relays.json b/temporary/bak/cfg/relays.json deleted file mode 100644 index 1ecb9fa..0000000 --- a/temporary/bak/cfg/relays.json +++ /dev/null @@ -1,41 +0,0 @@ -{ -"relays": - [ - { - "pin": 45, - "freq": 500, - "min": 0, - "max": 100, - "default": 0, - "vision": false, - "deltarate": 0 - }, - { - "pin": 48, - "freq": 500, - "min": 0, - "max": 100, - "default": 0, - "vision": false, - "deltarate": 0 - }, - { - "pin": 47, - "freq": 500, - "min": 0, - "max": 100, - "default": 0, - "vision": true, - "deltarate": 0 - }, - { - "pin": 21, - "freq": 500, - "min": 0, - "max": 100, - "default": 0, - "vision": true, - "deltarate": 0 - } - ] -} \ No newline at end of file diff --git a/temporary/bak/cfg/system.json b/temporary/bak/cfg/system.json deleted file mode 100644 index 429a075..0000000 --- a/temporary/bak/cfg/system.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "buttons": [ - { - "en": true, - "pin": 8 - }, - { - "en": true, - "pin": 19 - }, - { - "en": true, - "pin": 0 - } - ], - "oled": { - "en": false, - "height": 64, - "width": 128 - }, - "fan": { - "en": true, - "relay": 3 - }, - "t-sensor": { - "en": true, - "addr": 72, - "sp1": 85, - "fan-pwr1": 50, - "sp2": 90, - "fan-pwr2": 100, - "hyst": 1 - }, - "adc": { - "ain1_factor": 1.0 - } -} diff --git a/temporary/bak/cfg/touch-pins.json b/temporary/bak/cfg/touch-pins.json deleted file mode 100644 index d556439..0000000 --- a/temporary/bak/cfg/touch-pins.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "touchpins": - [ - { - "en": true, - "pin": 23, - "min": 100 - }, - { - "en": true, - "pin": 23, - "min": 100 - }, - { - "en": true, - "pin": 23, - "min": 100 - }, - { - "en": true, - "pin": 23, - "min": 100 - }, - { - "en": true, - "pin": 23, - "min": 100 - } - ] -} \ No newline at end of file diff --git a/temporary/bak/cfg/trx433.json b/temporary/bak/cfg/trx433.json deleted file mode 100644 index 6f9cac0..0000000 --- a/temporary/bak/cfg/trx433.json +++ /dev/null @@ -1,10 +0,0 @@ -{ -"rx433": { - "en": "true", - "pin": 38 - }, - "tx433": { - "en": "true", - "pin": 16 - } -} \ No newline at end of file diff --git a/temporary/bak/cfg/wifi.json b/temporary/bak/cfg/wifi.json deleted file mode 100644 index 550020c..0000000 --- a/temporary/bak/cfg/wifi.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "wifi": - { - "en": true, - "mdns-name": "atadev", - "host-name": "ATADeviceXX" - }, - "cred1": - { - "ssid": "DPWifi", - "pass": "dave3.14159" - }, - "cred2": - { - "ssid": "Default", - "pass": "password" - }, - "ap": - { - "ssid": "ATA_AP", - "pass": "12345678", - "ip": [192,168,10.1], - "gateway": [192,168,10,200], - "subnet": [255,255,255,0] - } -} \ No newline at end of file diff --git a/temporary/bak/www/edit.html b/temporary/bak/www/edit.html deleted file mode 100644 index af21eb6..0000000 --- a/temporary/bak/www/edit.html +++ /dev/null @@ -1,144 +0,0 @@ -{{NAVBAR}} - - - - Edit file - - - - - -

Edit file

-
- Editing file: {{SAVE_PATH_INPUT}} -
-
-
- -
-
- {{SAVE_PATH_INPUT}} - - - - -
-
-
- - - - - - \ No newline at end of file diff --git a/temporary/bak/www/edit2.html b/temporary/bak/www/edit2.html deleted file mode 100644 index a4edd4a..0000000 --- a/temporary/bak/www/edit2.html +++ /dev/null @@ -1,170 +0,0 @@ -{{NAVBAR}} - - - - Edit file - - - - - -

Edit file

- -
-
-
-
- -
-
-
- - -
-
- - -
-
-
-
-
- - - - \ No newline at end of file diff --git a/temporary/bak/www/event-box.js b/temporary/bak/www/event-box.js deleted file mode 100644 index f587666..0000000 --- a/temporary/bak/www/event-box.js +++ /dev/null @@ -1,420 +0,0 @@ -class EventBox extends HTMLElement { - constructor() { - super(); - this.attachShadow({ mode: 'open' }); - this.shadowRoot.innerHTML = ` - -
-
- Event0
-
-
- - -
-
- -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- -
-
- -
-
- `; - this.Title = this.shadowRoot.querySelector('#center-text'); - this.hueSelect = this.shadowRoot.querySelector('#hue-selector'); - this.AnimationList = this.shadowRoot.getElementById('animation-list'); - this.Speed = this.shadowRoot.getElementById('speed'); - this.HueRange = this.shadowRoot.querySelector('#huerange'); - this.Param1 = this.shadowRoot.querySelector('#param1'); - this.Param2 = this.shadowRoot.querySelector('#param2'); - this.Check1 = this.shadowRoot.querySelector('#check1'); - this.Check2 = this.shadowRoot.querySelector('#check2'); - this.Check3 = this.shadowRoot.querySelector('#check3'); - - this.AnimationListLabel = this.shadowRoot.querySelector('#list-label'); - this.SpeedLabel = this.shadowRoot.querySelector('#speed-label'); - this.HueRangeLabel = this.shadowRoot.querySelector('#huerange-label'); - this.Param1Label = this.shadowRoot.getElementById('param1-label'); - this.Param2Label = this.shadowRoot.getElementById('param2-label'); - this.Check1Label = this.shadowRoot.getElementById('check1-label'); - this.Check2Label = this.shadowRoot.getElementById('check2-label'); - this.Check3Label = this.shadowRoot.getElementById('check3-label'); - - this.AnimationPropsJson; - - this.SpeedCaption = ""; - this.HueRangeCaption = ""; - this.Param1Caption = ""; - this.Param2Caption = ""; - this.Check1Caption = ""; - this.Check2Caption = ""; - this.Check3Caption = ""; - - this.setSpeedCaption(`Speed: `); - this.Speed.min = 0; - this.Speed.max = 100; - - this.setHueRangeCaption(`Hue Range: `); - this.HueRange.min = 0; - this.HueRange.max = 360; - - this.setParam1Caption(`Param1: `); - this.Param1.min = 0; - this.Param1.max = 100; - - this.setParam2Caption(`Param2: `); - this.Param2.min = 0; - this.Param2.max = 100; - - this.setCheck1Caption(`Check1`); - this.setCheck2Caption(`Check2`); - this.setCheck2Caption(`Check3`); - - this.Index = 0; - - this.Speed.addEventListener('input', () => { this.updateSpeedLabel(); }); - this.HueRange.addEventListener('input', () => { this.updateHueRangeLabel(); }); - this.Param1.addEventListener('input', () => { this.updateParam1Label(); }); - this.Param2.addEventListener('input', () => { this.updateParam2Label(); }); - - this.TryButton = this.shadowRoot.querySelector('#try-button'); - this.TryButton.addEventListener('click', () => { - this.handleTryButtonClick(); - }); - - this.AnimationList.addEventListener('change', this.handleAnimationListChange.bind(this)); - } - - setIndex(i){ this.Index = i; } - getIndex(){ return this.Index; } - updateSpeedLabel(){ - if(!this.Speed.hidden){ - this.SpeedLabel.innerHTML = this.SpeedCaption + this.getSpeedValue(); - } - } - updateHueRangeLabel(){ - if(!this.HueRange.hidden){ - this.HueRangeLabel.innerHTML = this.HueRangeCaption + this.getHueRangeValue(); - } - } - updateParam1Label(){ - if(!this.Param1.hidden){ - this.Param1Label.innerHTML = this.Param1Caption + this.getParam1Value(); - } - } - updateParam2Label(){ - if(!this.Param2.hidden){ - this.Param2Label.innerHTML = this.Param2Caption + this.getParam2Value(); - } - } - setTitle(text){ - this.Title.textContent = text; - } - addOptionToList(value, text){ - const optionElement = document.createElement('option'); - optionElement.value = value; - optionElement.textContent = text; - this.AnimationList.appendChild(optionElement); - } - setHidden(hidden){ this.hidden = hidden; } - getHidden(){ return this.hidden; } - setHueValue(value){ this.hueSelect.setHue(value); } - getHueValue(){ return this.hueSelect.getSelectedHue(); } - setSpeedValue(value){ - this.Speed.value = value; - this.updateSpeedLabel(); - } - setSpeedCaption(caption){ - let hid = false; - if(caption.trim() === ""){ - hid = true; - } - this.SpeedCaption = caption; - this.SpeedLabel.innerHTML = caption; - this.Speed.hidden = hid; - this.SpeedLabel.hidden = hid; - } - getSpeedValue(){ return this.Speed.value; } - setHueRangeValue(value){ - this.HueRange.value = value; - this.updateHueRangeLabel() - } - setHueRangeCaption(caption){ - let hid = false; - if(caption.trim() === ""){ - hid = true; - } - this.HueRangeCaption = caption; - this.HueRangeLabel.innerHTML = caption; - this.HueRange.hidden = hid; - this.HueRangeLabel.hidden = hid; - } - getHueRangeValue(){ return this.HueRange.value; } - setParam1Value(value){ - this.Param1.value = value; - this.updateParam1Label() - } - setParam1Caption(caption){ - let hid = false; - if(caption.trim() === ""){ - hid = true; - } - this.Param1Caption = caption; - this.Param1Label.innerHTML = caption; - this.Param1.hidden = hid; - this.Param1Label.hidden = hid; - } - getParam1Value(){ return this.Param1.value; } - setParam2Value(value){ - this.Param2.value = value; - this.updateParam2Label() - } - setParam2Caption(caption){ - let hid = false; - if(caption.trim() === ""){ - hid = true; - } - this.Param2Caption = caption; - this.Param2Label.innerHTML = caption; - this.Param2.hidden = hid; - this.Param2Label.hidden = hid; - } - getParam2Value(){ return this.Param2.value; } - - setCheck1Value(value){ this.Check1.checked = value; } - setCheck1Caption(caption){ - let hid = false; - if(caption.trim() === ""){ - hid = true; - } - this.Check1Label.innerHTML = caption; - this.Check1.hidden = hid; - this.Check1Label.hidden = hid; - } - getCheck1Value(){ return this.Check1.checked; } - - setCheck2Value(value){ this.Check2.checked = value; } - setCheck2Caption(caption){ - let hid = false; - if(caption.trim() === ""){ - hid = true; - } - this.Check2Label.innerHTML = caption; - this.Check2.hidden = hid; - this.Check2Label.hidden = hid; - } - getCheck2Value(){ return this.Check2.checked; } - - setCheck3Value(value){ this.Check3.checked = value; } - setCheck3Caption(caption){ - let hid = false; - if(caption.trim() === ""){ - hid = true; - } - this.Check3Label.innerHTML = caption; - this.Check3.hidden = hid; - this.Check3Label.hidden = hid; - } - getCheck3Value(){ return this.Check3.checked; } - - setAnimationIndex(index){ - this.AnimationList.selectedIndex = index; - const changeEvent = new Event('change'); - this.AnimationList.dispatchEvent(changeEvent); - } - getAnimationIndex(){ - return this.AnimationList.selectedIndex; - } - - handleTryButtonClick() { - const eventIndexValue = this.getIndex(); - const animIndexValue = this.getAnimationIndex(); - const hueValue = this.getHueValue(); - const speedValue = this.getSpeedValue(); - const colorRangeValue = this.getHueRangeValue(); - const param1Value = this.getParam1Value(); - const param2Value = this.getParam2Value(); - const check1Value = this.getCheck1Value(); - const check2Value = this.getCheck2Value(); - const check3Value = this.getCheck3Value(); - - this.dispatchEvent(new CustomEvent('tryClick', { - detail: { - eventIndex: eventIndexValue, - animIndex: animIndexValue, - hue: hueValue, - speed: speedValue, - colorRange: colorRangeValue, - param1: param1Value, - param2: param2Value, - check1: check1Value, - check2: check2Value, - check3: check2Value - } - })); - } - - setAnimationCaptions(propsJson){ - this.AnimationPropsJson = propsJson; - - //add options to list - let x = 0; - this.AnimationPropsJson.forEach(props => { - this.addOptionToList(x, props.name); - x++; - }); - - } - - handleAnimationListChange(){ - const selectedIndex = this.getAnimationIndex(); - const selectedProps = this.AnimationPropsJson[selectedIndex]; - - this.updateControlProps(selectedProps); - } - - updateControlProps(props){ - this.setSpeedCaption(props.speed); - let s = props['hue-range']; - this.setHueRangeCaption(s || ""); - this.setParam1Caption(props.param1 || ""); - this.setParam2Caption(props.param2 || ""); - this.setCheck1Caption(props.check1 || ""); - this.setCheck2Caption(props.check2 || ""); - this.setCheck3Caption(props.check3 || ""); - - this.updateSpeedLabel(); - this.updateHueRangeLabel(); - this.updateParam1Label(); - this.updateParam2Label(); - } - -} - -customElements.define('event-box', EventBox); - \ No newline at end of file diff --git a/temporary/bak/www/failed.html b/temporary/bak/www/failed.html deleted file mode 100644 index a092d0c..0000000 --- a/temporary/bak/www/failed.html +++ /dev/null @@ -1,24 +0,0 @@ -{{NAVBAR}} - - - - Update Failed - - - - - -
-

The update has failed.

-
- -
- - \ No newline at end of file diff --git a/temporary/bak/www/files.html b/temporary/bak/www/files.html deleted file mode 100644 index b0f7f69..0000000 --- a/temporary/bak/www/files.html +++ /dev/null @@ -1,311 +0,0 @@ -{{NAVBAR}} - - - - File Manager - - - - - - - -

File Manager

- -
- File list -
-

  Total: {{FS_TOTAL_BYTES}}, Used: {{FS_USED_BYTES}}, Available: {{FS_FREE_BYTES}}

-
- - {{LISTED_FILES}} -
Listing: Size:
-
-
- -
- -
- File upload -
-
- - - - - - - - - - - -
-
-    - -
-
-
- -
-
-
- -
- -
- Edit file -
-
- - - -
-
-
-
- -
- -
- Delete file -
-
- - - -
-
-
-
- -
- - - -

Firmware/File System Update

- -
- Firmware Update (Local) | Firmware Ver: {{FIRM_VER}}
File name fwataVxxx.bin or lfsataVxxx.bin
-
-
- - - - - -
- - - -
- -
- - -
- - - -
-
-
- -
- - -
-
-
-
-
-
- - - - - - - \ No newline at end of file diff --git a/temporary/bak/www/global-style.css b/temporary/bak/www/global-style.css deleted file mode 100644 index 442f988..0000000 --- a/temporary/bak/www/global-style.css +++ /dev/null @@ -1,74 +0,0 @@ -body { - /*background-color: #f7f7f7;*/ - font-family: Tahoma, Arial, sans-serif; - font-size: small; - margin: 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: flex-start; -} -h1 { - margin-top: 0; -} -input{ - cursor:pointer; -} -input[type="number"]{ - width: 100px; -} -#submit { - width:120px; -} -select{ - width:160px; -} -#select-path { - width:250px; -} -#select-dir { - width:90px; -} -#spacer-50 { - height: 50px; -} -#spacer-20 { - height: 20px; -} -#spacer-10 { - height: 10px; -} -table { - /*background-color: #dddddd;*/ - border-collapse: collapse; - width:600px; - margin: 0 auto; - overflow: visible; -} -td, th { - /*border: 1px solid #dddddd;*/ - text-align: left; - padding: 2px; -} -#first_td_th { - width:400px; -} -fieldset { - width:620px; - /*background-color: #f7f7f7;*/ - border-radius: 10px; - border-color: blue; -} -#format-notice { - color: #ff0000; -} -legend { - display: flex; - justify-content: center; - background-color:white; - background-blend-mode: darken; - border-radius: 10px; - padding: 1px 8px 2px 8px; - border-style: solid; - border-width: 1.0; -} \ No newline at end of file diff --git a/temporary/bak/www/home.html b/temporary/bak/www/home.html deleted file mode 100644 index 86a0873..0000000 --- a/temporary/bak/www/home.html +++ /dev/null @@ -1,271 +0,0 @@ -{{NAVBAR}} - - - - - - - Welcome - - - - -

ATA Booth Summary

- -
- Booth Overview -
- - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
-
-
- - - - - -
-
-
- ... - - ... - - -
-
-
- -
- -
- System Info: -
- - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
-
-
- - - - - -
-
-
- - - ... - - -
-
-
- -
- -
- Network / WiFi -
- - - - - - - - - - - - - - -
- - - - - -
-
-
- - - - - -
-
-
- -
- -
- Bluetooth LE -
- - - - - - - -
- - - - - -
-
-
- - - - \ No newline at end of file diff --git a/temporary/bak/www/hue-select.js b/temporary/bak/www/hue-select.js deleted file mode 100644 index bcc8132..0000000 --- a/temporary/bak/www/hue-select.js +++ /dev/null @@ -1,275 +0,0 @@ - -// Define the HueSelect custom element -class HueSelect extends HTMLElement { - constructor() { - super(); - this.attachShadow({ mode: 'open' }); - this.shadowRoot.innerHTML = ` - - - `; - - this.currentHue = 0; - this.colorList; - this.hueLabel = this.shadowRoot.getElementById('hue-label'); - - const selectedColorDiv = this.shadowRoot.getElementById('selectedColor'); - const colorPatch = selectedColorDiv.querySelector('.color-patch'); - - /* colorPatch.addEventListener('mouseenter', () => { - const dropdownContent = this.shadowRoot.querySelector('.dropdown-content'); - dropdownContent.style.display = 'block'; - }); */ - - // Add the global click event listener to hide the color picker dropdown - /* - window.addEventListener('click', (event) => { - const dropdownContent = this.shadowRoot.querySelector('.dropdown-content'); - if (!event.target.closest('.dropdown')) { - dropdownContent.style.display = 'none'; - } - }); */ - - selectedColorDiv.addEventListener('click', () => { - const dropdownContent = this.shadowRoot.querySelector('.dropdown-content'); - dropdownContent.style.display = dropdownContent.style.display === 'block' ? 'none' : 'block'; - }); - - // Generate the color options and add them to the dropdown - this.createColorOptions(); - this.setHue(0); - } - - generateColors() { - const colors = []; - for (let hue = 0; hue <= 360; hue += 10) { - if (hue == 360) { hue = 359; } - colors.push(hue); - } - - colors.push(-1); - colors.push(-2); - return colors; - } - - createColorOption(hue) { - const colorOption = document.createElement('div'); - colorOption.classList.add('color-option'); - - const colorPatch = document.createElement('span'); - colorPatch.classList.add('color-patch'); - - const colorText = document.createElement('span'); - colorText.classList.add('color-text'); - colorText.textContent = hue; - - const rgbHex = document.createElement('span'); - rgbHex.classList.add('rgb-hex'); - - if (hue === -2) { - colorPatch.style.backgroundColor = 'rgb(0,0,0)'; - rgbHex.innerHTML = '  #000000'; - } else if (hue === -1) { - colorPatch.style.backgroundColor = 'rgb(255,255,255)'; - rgbHex.innerHTML = '  #FFFFFF'; - } else { - colorPatch.style.backgroundColor = `hsl(${hue}, 100%, 50%)`; - const hexColor = this.hslToRgb(hue, 100, 50).toUpperCase(); - rgbHex.innerHTML = `  ${hexColor}`; - } - - colorOption.appendChild(colorPatch); - colorOption.appendChild(colorText); - colorOption.appendChild(rgbHex); - - // Add click event listener to each color option - colorOption.addEventListener('click', () => this.handleColorSelection(hue)); - - return colorOption; - } - - createColorOptions() { - const dropdownContent = this.shadowRoot.querySelector('.dropdown-content'); - this.colorList = this.generateColors(); - - this.colorList.forEach(hue => { - const colorOption = this.createColorOption(hue); - dropdownContent.appendChild(colorOption); - }); - - // Create elements for white and black colors - //const whiteColorOption = this.createColorOption(-1); - //dropdownContent.appendChild(whiteColorOption); - - //const blackColorOption = this.createColorOption(-2); - //dropdownContent.appendChild(blackColorOption); - } - - // Function to convert HSL to RGB - hslToRgb(h, s, l) { - h /= 360; - s /= 100; - l /= 100; - let r, g, b; - if (s === 0) { - r = g = b = l; // achromatic - } else { - const hue2rgb = (p, q, t) => { - if (t < 0) t += 1; - if (t > 1) t -= 1; - if (t < 1 / 6) return p + (q - p) * 6 * t; - if (t < 1 / 2) return q; - if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; - return p; - }; - const q = l < 0.5 ? l * (1 + s) : l + s - l * s; - const p = 2 * l - q; - r = hue2rgb(p, q, h + 1 / 3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1 / 3); - } - const toHex = (x) => { - const hex = Math.round(x * 255).toString(16); - return hex.length === 1 ? '0' + hex : hex; - }; - return `#${toHex(r)}${toHex(g)}${toHex(b)}`; - } - - - handleColorSelection(hue) { - this.currentHue = hue; - const selectedColorDiv = this.shadowRoot.getElementById('selectedColor'); - const colorPatch = selectedColorDiv.querySelector('.color-patch'); - - // Update the color patch and hue label - const rgb = this.getRGBfromHue(hue); - colorPatch.style.backgroundColor = rgb; - //console.log(colorPatch.style.backgroundColor); - this.setHueLabel(hue); - this.hideDropdown(); - - // Dispatch a 'change' event with the selected hue value - this.dispatchEvent(new CustomEvent('change', { detail: { hue, rgb } })); - } - - // Method to get the hue value of the selected item - getSelectedHue() { - return this.currentHue; - } - - getSelectedRGB() { - const selectedColorText = this.shadowRoot.getElementById('selectedColor').textContent.trim(); - return parseFloat(selectedColorText); - } - - getRGBfromHue(hue){ - if(hue == -1){ - return '#FFFFFF'; - }else if(hue == -2){ - return '#000000'; - }else{ - return this.hslToRgb(hue, 100, 50);; - } - } - // Method to get the RGB value of the selected item - getSelectedRgb() { - const selectedHue = this.getSelectedHue(); - return getRGBfromHue(selectedHue); - } - - setHue(hue) { - // Round the input hue to the nearest 10th - let roundedHue = hue; - if(hue === -1 || hue === -2){ - roundedHue = hue; - }else{ - roundedHue = Math.round(hue / 10) * 10; - if (roundedHue >= 360) { - roundedHue = 359; - } - - if (roundedHue < 0) { - roundedHue = 0; - } - } - - this.currentHue = roundedHue; - - this.colorList.forEach(colorVal => { - if (colorVal === roundedHue) { - this.handleColorSelection(roundedHue); - } - }); - - this.hideDropdown(); - } - - hideDropdown() { - const dropdownContent = this.shadowRoot.querySelector('.dropdown-content'); - dropdownContent.style.display = 'none'; - } - - setHueLabel(value){ - this.hueLabel.textContent = "Hue: " + value; - } - - - } - - - - // Register the custom element - customElements.define('hue-select', HueSelect); - \ No newline at end of file diff --git a/temporary/bak/www/label.html b/temporary/bak/www/label.html deleted file mode 100644 index 6593d48..0000000 --- a/temporary/bak/www/label.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - -Event Container - - - -
-
- -
-
- - - - \ No newline at end of file diff --git a/temporary/bak/www/lights.html b/temporary/bak/www/lights.html deleted file mode 100644 index 24814d8..0000000 --- a/temporary/bak/www/lights.html +++ /dev/null @@ -1,452 +0,0 @@ -{{NAVBAR}} - - - - - - - - - - - - -
-

Lights Configuration

- -
- Saved Animation Profiles -
-
- - -
-
- - - -
-
-
-
- -
-
- Countdown ( Constant Light ) -
-
- - -
-
- - -
-
-
-
-
- -
-
-
- - -
-
-
-
- -
- - - - diff --git a/temporary/bak/www/navbar.html b/temporary/bak/www/navbar.html deleted file mode 100644 index 3c23772..0000000 --- a/temporary/bak/www/navbar.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - -
- -
- - \ No newline at end of file diff --git a/temporary/bak/www/ok.html b/temporary/bak/www/ok.html deleted file mode 100644 index a5263dd..0000000 --- a/temporary/bak/www/ok.html +++ /dev/null @@ -1,24 +0,0 @@ -{{NAVBAR}} - - - - Update Success - - - - - -
-

The update was successful.

-
- -
- - \ No newline at end of file diff --git a/temporary/bak/www/setup.html b/temporary/bak/www/setup.html deleted file mode 100644 index 2cfaa4e..0000000 --- a/temporary/bak/www/setup.html +++ /dev/null @@ -1,355 +0,0 @@ -{{NAVBAR}} - - - - Booth Configuration Tools - - - - - - -

System Setup

-
- -
- LED Strip #1 Settings -
-
-
- -
-
- -
-
- -
-
-
- -
- LED Strip #1 Settings -
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
- - -
- Test Tool - -
-
- -
-
- -
- -
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
- - -
- Luma Stiks - -
-
-
- -
-
-
- -
-
- -
-
-
- -
-
-
- -
-
- -
-
-
- -
-
-
- -
-
- -
-
- -
- -
-
- -
- - - - \ No newline at end of file diff --git a/temporary/bak/www/wifi.html b/temporary/bak/www/wifi.html deleted file mode 100644 index 58f9781..0000000 --- a/temporary/bak/www/wifi.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - - WiFi Credentials - - - -

Enter WiFi Credentials

-
- - - - - - Image not found -
- - - - diff --git a/temporary/my_buzzer.cpp b/temporary/my_buzzer.cpp deleted file mode 100644 index e686da2..0000000 --- a/temporary/my_buzzer.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include "my_buzzer.h" -#include -#include - -#include -#include -#include - -#include "JsonConstrain.h" -#include "global.h" - -const char* DEFAULT_MELODY = "Ack:d=16,o=5,b=200:c,e,g"; - -// serial debugging enabled -//#define ANY_RTTTL_INFO - -static const char* tag = "buzzer"; - -BUZZ_TUNE buzzTune[TUNE_MAX_COUNT]; -int8_t buzzPin; -int8_t buzzerChannel = -1; // Store the LEDC channel used by the buzzer - -// File-scope state for tune management (minimal overhead) -static volatile int prev_tune = -1; -static volatile bool buzzer_busy = false; - -// Optimized tone functions - minimal overhead, no logging -void buzzerTone(uint8_t pin, unsigned int frequency, unsigned long duration) { - if (buzzerChannel >= 0 && frequency > 0) { - ledcWriteTone(buzzerChannel, frequency); - } -} - -void buzzerNoTone(uint8_t pin) { - if (buzzerChannel >= 0) { - ledcWrite(buzzerChannel, 0); - } -} - -void Init_Buzzer(int8_t pin, const char* configFile, int8_t channel) -{ - buzzPin = pin; - if(buzzPin >= 0){ - pinMode(buzzPin, OUTPUT); - - // If channel is not provided, find an unused one - if (channel < 0) { - buzzerChannel = findUnusedLedcChannel(); - if (buzzerChannel < 0) { - ESP_LOGE(tag, "No available LEDC channel for buzzer"); - return; - } - } else { - // Use the provided channel and mark it as used - extern bool markLedcChannelUsed(int ch); // Function from global.cpp - if (markLedcChannelUsed(channel)) { - buzzerChannel = channel; - } else { - ESP_LOGE(tag, "Requested channel %d is already in use, finding alternative", channel); - buzzerChannel = findUnusedLedcChannel(); - if (buzzerChannel < 0) { - ESP_LOGE(tag, "No available LEDC channel for buzzer"); - return; - } - } - } - - // Set up the channel for the buzzer with proper audio frequency range - ledcSetup(buzzerChannel, 2000, 10); // 2000 Hz base, 10-bit resolution for better frequency range - ledcAttachPin(buzzPin, buzzerChannel); - - // Test the channel is working - ESP_LOGI(tag, "Testing buzzer channel %d...", buzzerChannel); - ledcWriteTone(buzzerChannel, 1000); // Test tone - delay(100); - ledcWrite(buzzerChannel, 0); // Stop test tone - - // Set custom tone functions for anyrtttl - anyrtttl::setToneFunction(buzzerTone); - anyrtttl::setNoToneFunction(buzzerNoTone); - - ESP_LOGI(tag, "Buzzer hardware initialized on pin %d using LEDC channel %d", buzzPin, buzzerChannel); - } - - Buzzer_Load_Tunes(configFile); // Load Tunes - ESP_LOGI(tag, "Buzzer initialized on pin %d, channel %d", buzzPin, buzzerChannel); -} - -int8_t Buzzer_Get_Channel() { - return buzzerChannel; -} - -void Buzzer_Play_Tune(TUNE_TYPE tune, bool async, bool hasPriority) -{ - // Fast path checks - minimal overhead - if (buzzPin < 0 || buzzerChannel < 0) { - ESP_LOGW(tag, "Buzzer not initialized - pin:%d, channel:%d", buzzPin, buzzerChannel); - return; - } - if (tune < 0 || tune >= TUNE_MAX_COUNT) { - ESP_LOGW(tag, "Invalid tune index: %d (max: %d)", (int)tune, TUNE_MAX_COUNT); - return; - } - - // Direct reference to avoid String copying - const String& melody = buzzTune[tune].melody; - if (melody.isEmpty()) { - ESP_LOGW(tag, "Empty melody for tune %d", (int)tune); - return; - } - - ESP_LOGI(tag, "Playing tune %d: %s (async=%d, priority=%d)", (int)tune, melody.c_str(), async, hasPriority); - - // Simple atomic check for thread safety without mutex overhead - if (buzzer_busy && !hasPriority) { - ESP_LOGD(tag, "Buzzer busy, skipping tune %d", (int)tune); - return; - } - - // Async mode: minimal state management - if (async) { - bool playing = anyrtttl::nonblocking::isPlaying(); - if (hasPriority && playing) { - ESP_LOGD(tag, "Stopping current tune for priority tune %d", (int)tune); - anyrtttl::nonblocking::stop(); - playing = false; - } - if (!playing || prev_tune != tune) { - ESP_LOGI(tag, "Starting async tune %d", (int)tune); - anyrtttl::nonblocking::begin(buzzPin, melody.c_str()); - prev_tune = tune; - } - anyrtttl::nonblocking::play(); - return; - } - - // Blocking mode: minimal cycles with yield for multitasking - ESP_LOGI(tag, "Playing blocking tune %d, cycles=%d", (int)tune, buzzTune[tune].cycles); - buzzer_busy = true; - const int cycles = buzzTune[tune].cycles; - const int pause_ms = buzzTune[tune].pause; - - for (int c = 0; c < cycles; ++c) { - anyrtttl::blocking::play(buzzPin, melody.c_str()); - if (pause_ms > 0 && c + 1 < cycles) { - delay(pause_ms); - } - yield(); // Allow other tasks to run - } - - prev_tune = tune; - buzzer_busy = false; - ESP_LOGI(tag, "Finished playing tune %d", (int)tune); -} - -// Optimized beep function - minimal overhead -void Buzzer_Beep(int mSecs, int freq) -{ - if (buzzPin < 0 || buzzerChannel < 0) return; - - ledcWriteTone(buzzerChannel, freq); - delay(mSecs); - ledcWrite(buzzerChannel, 0); -} - -// Test function to verify buzzer functionality -void Buzzer_Test() { - if (buzzPin < 0 || buzzerChannel < 0) { - ESP_LOGE(tag, "Cannot test buzzer - not initialized"); - return; - } - - ESP_LOGI(tag, "Testing buzzer..."); - - // Test direct LEDC control - ESP_LOGI(tag, "Test 1: Direct LEDC tones"); - for (int freq = 500; freq <= 2000; freq += 500) { - ESP_LOGI(tag, "Playing %d Hz", freq); - ledcWriteTone(buzzerChannel, freq); - delay(200); - ledcWrite(buzzerChannel, 0); - delay(100); - } - - // Test custom tone functions - ESP_LOGI(tag, "Test 2: Custom tone functions"); - buzzerTone(buzzPin, 1000, 500); - delay(500); - buzzerNoTone(buzzPin); - - // Test anyrtttl with a simple melody - ESP_LOGI(tag, "Test 3: anyrtttl blocking play"); - anyrtttl::blocking::play(buzzPin, DEFAULT_MELODY); - - ESP_LOGI(tag, "Buzzer test complete"); -} - -// Optimized tune loading - minimal memory allocation -void Buzzer_Load_Tunes(const char* tunesPath){ - ESP_LOGI(tag, "Loading tunes from: %s", tunesPath); - File file = LittleFS.open(tunesPath); - if (!file) { - ESP_LOGW(tag, "Could not open %s, using default tune", tunesPath); - // Set default tune only at index 0 - buzzTune[0].cycles = 1; - buzzTune[0].pause = 0; - buzzTune[0].melody = DEFAULT_MELODY; - ESP_LOGI(tag, "Loaded default tune at index 0: %s", DEFAULT_MELODY); - return; - } - - // Use smaller JSON document for memory efficiency - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - - if(error){ - ESP_LOGE(tag, "JSON parse error: %s", error.c_str()); - // Set default tune on error - buzzTune[0].cycles = 1; - buzzTune[0].pause = 0; - buzzTune[0].melody = DEFAULT_MELODY; - ESP_LOGI(tag, "Loaded default tune due to JSON error: %s", DEFAULT_MELODY); - return; - } - - JsonArray tuneJsonArray = doc["tunes"]; - if(!tuneJsonArray.isNull()){ - int tuneIndex = 0; - for(JsonObject obj : tuneJsonArray){ - if(tuneIndex >= TUNE_MAX_COUNT) break; - buzzTune[tuneIndex].cycles = jsonConstrain(tag, obj, "cycles", 1, 100, 1); - buzzTune[tuneIndex].pause = jsonConstrain(tag, obj, "pause", 0, 100, 0); - buzzTune[tuneIndex].melody = jsonConstrainString(tag, obj, "tune", DEFAULT_MELODY); - ESP_LOGI(tag, "Loaded tune %d: cycles=%d, pause=%d, melody=%.40s...", - tuneIndex, buzzTune[tuneIndex].cycles, buzzTune[tuneIndex].pause, - buzzTune[tuneIndex].melody.c_str()); - tuneIndex++; - } - ESP_LOGI(tag, "Successfully loaded %d tunes", tuneIndex); - } else { - ESP_LOGW(tag, "No 'tunes' array found in JSON"); - // Set default tune if no tunes array found - buzzTune[0].cycles = 1; - buzzTune[0].pause = 0; - buzzTune[0].melody = DEFAULT_MELODY; - ESP_LOGI(tag, "Loaded default tune: %s", DEFAULT_MELODY); - } -} \ No newline at end of file diff --git a/test/edit.html b/test/edit.html new file mode 100644 index 0000000..7f478e8 --- /dev/null +++ b/test/edit.html @@ -0,0 +1,265 @@ + + + + Edit file + + + + + + + + + + +
+

Edit File

+ +
+
Editor
+ +
+ +
+ + + + +
+ + +
+ +
+
+
+
+ + + + diff --git a/test/files.html b/test/files.html new file mode 100644 index 0000000..55fcee0 --- /dev/null +++ b/test/files.html @@ -0,0 +1,350 @@ + + + + File Manager + + + + + + + + + + +
+

File Manager

+ +
+ File List +

Total: {{FS_TOTAL_BYTES}}, Used: {{FS_USED_BYTES}}, Available: {{FS_FREE_BYTES}}

+ + + + + + + + + {{LISTED_FILES}} + +
Listing:Size:
+
+ +
+
File Upload
+
+
+ +
+
+ + +
+
+
+ +
+
Edit File
+
+
+ + +
+
+
+ +
+
Delete File
+
+
+ + +
+
+
+ +
+ + + + \ No newline at end of file diff --git a/webSock/AppUpgrade.cpp b/webSock/AppUpgrade.cpp deleted file mode 100644 index d3a2857..0000000 --- a/webSock/AppUpgrade.cpp +++ /dev/null @@ -1,522 +0,0 @@ -#include "AppUpgrade.h" -#include "esp_log.h" -#include -#include -#include -#include "global.h" -#include "jsonConstrain.h" - -static const char* TAG = "AppUpdater"; -TaskHandle_t Update_Task_Handle = NULL; - -// Queue handle for firmware update messages -//QueueHandle_t updateMsgQueue = NULL; - - -bool Version::operator<(const Version& other) const { - if (major != other.major) return major < other.major; - if (minor != other.minor) return minor < other.minor; - return patch < other.patch; -} - -String Version::toString() const { - return String(major) + "." + String(minor) + "." + String(patch); -} - -AppUpdater::AppUpdater(fs::FS& fs, const char* currVersion, const char* bucket, const char* manifestName, const char* appBin) - : currentVersion(currVersion), bucketUrl(bucket), manifestName(manifestName), appName(appBin), fileSystem(fs), downloadBuffer(new uint8_t[BUFFER_SIZE]) -{ - ESP_LOGI(TAG, "AppUpdater initialized with version %s", currVersion); -} - -void AppUpdater::setProgressCallback(void (*callback)( UpdateStatus status, int percentage, const char* message)) { - progressCb = callback; -} - -void AppUpdater::updateProgress(UpdateStatus newStatus, int percentage, const char* message) { - status = newStatus; - if (progressCb) { - progressCb(status, percentage, message); - } -} - -bool AppUpdater::checkManifest() { - String url = String(bucketUrl) + manifestName; - ESP_LOGD(TAG, "Fetching manifest from: %s", url.c_str()); - - // Start the HTTP client and Send GET request for manifest - HTTPClient http; - http.begin(url); - int httpCode = http.GET(); - if (httpCode != HTTP_CODE_OK) { - ESP_LOGE(TAG, "HTTP GET failed, error: %d", httpCode); - http.end(); - return false; - } - - // Read the response - String payload = http.getString(); - http.end(); - - // Parse JSON - DeserializationError error = deserializeJson(jsonManifest, payload); - if (error) { - ESP_LOGE(TAG, "Failed to parse manifest: %s", error.c_str()); - return false; - } - - // Check for version section - JsonObject jsonVersion = jsonManifest["version"]; - if (jsonVersion.isNull()) { - ESP_LOGE(TAG, "No version section in manifest"); - return false; - } - - // Get the remote version - int major = jsonVersion["major"] | 0; - int minor = jsonVersion["minor"] | 0; - int patch = jsonVersion["patch"] | 0; - Version remoteVersion = {major, minor, patch}; - - Version localVersion; - sscanf(currentVersion, "%d.%d.%d", &localVersion.major, &localVersion.minor, &localVersion.patch); - - // Check if an update is available - if (remoteVersion < localVersion) { - ESP_LOGI(TAG, "No updates available"); - return false; - } - - ESP_LOGD(TAG, "Manifest content: %s", payload.c_str()); - - return true; -} - -bool AppUpdater::updateFile(const char* remotePath, const char* localPath, const char* expectedMd5) { - updateProgress(UpdateStatus::DOWNLOADING, 0, localPath); - - // Construct full URL - String url = String(bucketUrl) + remotePath; - ESP_LOGD(TAG, "Downloading: %s -> %s", url.c_str(), localPath); - - String localMd5 = getLocalMD5(localPath); - - if (localMd5.equals(expectedMd5)) { - ESP_LOGI(TAG, "File already up to date: %s", localPath); - updateProgress(UpdateStatus::SKIPPING, 100, localPath); - return true; - } - - // Start the download - HTTPClient http; - http.begin(url); - int httpCode = http.GET(); - if (httpCode != HTTP_CODE_OK) { - ESP_LOGE(TAG, "Download failed: %d", httpCode); - updateProgress(UpdateStatus::ERROR, 0); - http.end(); - return false; - } - - // Get the stream and content length - WiFiClient* stream = http.getStreamPtr(); - size_t contentLength = http.getSize(); - - // Verify and save the file - bool success = verifyAndSaveFile(stream, contentLength, localPath, expectedMd5); - http.end(); - - updateProgress(success ? UpdateStatus::COMPLETE : UpdateStatus::ERROR, 100, localPath); - return success; -} - -bool AppUpdater::verifyAndSaveFile(WiFiClient* stream, size_t contentLength, const char* localPath, const char* expectedMd5) -{ - MD5Builder md5; - md5.begin(); - size_t totalRead = 0; - - // Create temporary filename - String tempPath = String(localPath) + ".tmp"; - - // Open temporary file for writing - File file = fileSystem.open(tempPath.c_str(), FILE_WRITE); - if (!file) { - ESP_LOGE(TAG, "Failed to open temporary file for writing"); - return false; - } - - updateProgress(UpdateStatus::DOWNLOADING, 0, localPath); - - // Single pass: Save file and calculate MD5 - while (totalRead < contentLength) { - size_t available = stream->available(); - if (available) { - size_t readLen = stream->readBytes(downloadBuffer.get(), std::min(available, size_t(BUFFER_SIZE))); - - // Write to temp file and update MD5 - if (file.write(downloadBuffer.get(), readLen) != readLen) { - ESP_LOGE(TAG, "Failed to write to temporary file"); - - file.close(); - fileSystem.remove(tempPath.c_str()); - return false; - } - - md5.add(downloadBuffer.get(), readLen); - totalRead += readLen; - updateProgress(UpdateStatus::DOWNLOADING, (totalRead * 90) / contentLength , localPath); - } - yield(); - } - - file.close(); - md5.calculate(); - String calculatedMd5 = md5.toString(); - - // Verify MD5 hash - if (!calculatedMd5.equals(expectedMd5)) { - ESP_LOGE(TAG, "MD5 mismatch for %s", localPath); - fileSystem.remove(tempPath.c_str()); - return false; - } - - // Replace original file with verified temp file - if (fileSystem.exists(localPath)) { - fileSystem.remove(localPath); - } - if (!fileSystem.rename(tempPath.c_str(), localPath)) { - ESP_LOGE(TAG, "Failed to rename temporary file"); - fileSystem.remove(tempPath.c_str()); - return false; - } - - updateProgress(UpdateStatus::COMPLETE, 100, localPath); - return true; -} - -String AppUpdater::getLocalMD5(const char* filePath){ - File file = fileSystem.open(filePath, "r"); - if(!file){ - ESP_LOGE(TAG, "Error opening %s...", filePath); - return String(); - } - - MD5Builder md5Builder; - md5Builder.begin(); - size_t fileSize = file.size(); - size_t totalRead = 0; - size_t readLen = 0; - while (totalRead < fileSize) { - readLen = file.readBytes(reinterpret_cast(downloadBuffer.get()), std::min(fileSize - totalRead, size_t(BUFFER_SIZE))); - md5Builder.add(downloadBuffer.get(), readLen); - totalRead += readLen; - } - - md5Builder.calculate(); - file.close(); - return md5Builder.toString(); -} - -bool AppUpdater::updateFilesArray() { - int successCount = 0; - int totalFiles = jsonFilesArray.size(); - ESP_LOGI(TAG, "Found %d files in manifest", totalFiles); - - // Iterate over each file entry in the manifest - for (JsonObject file : jsonFilesArray) { - const char* remotePath = file["remote"]; - const char* localPath = file["local"]; - const char* expectedMd5 = file["md5"]; - - // Skip invalid entries - if (!remotePath || !localPath || !expectedMd5) { - ESP_LOGE(TAG, "Invalid file entry in manifest"); - continue; - } - - // Attempt to update the file - if (updateFile(remotePath, localPath, expectedMd5)) { - successCount++; - } - } - - ESP_LOGI(TAG, "Manifest update complete: %d/%d files updated", successCount, totalFiles); - return successCount == totalFiles; -} - -bool AppUpdater::updateApp() { - updateProgress(UpdateStatus::MESSAGE, 0, "Starting firmware update"); - - // Check for firmware section in manifest - if (!jsonManifest["firmware"].is() || !jsonManifest["firmware"]["md5"].is()) { - ESP_LOGE(TAG, "Invalid firmware section in manifest"); - updateProgress(UpdateStatus::MESSAGE, 0, "Firmware: Invalid firmware section in manifest"); - return false; - } - - // Get the firmware MD5 hash and URL - const char* expectedMd5 = jsonManifest["firmware"]["md5"]; - String firmwareUrl = String(bucketUrl) + appName; - - // Download the firmware - HTTPClient http; - http.begin(firmwareUrl); - int httpCode = http.GET(); - if (httpCode != HTTP_CODE_OK) { - ESP_LOGE(TAG, "Firmware download failed: %d", httpCode); - updateProgress(UpdateStatus::MESSAGE, 0, "Firmware: Firmware download failed"); - http.end(); - return false; - } - - // Check available space - size_t firmwareSize = http.getSize(); - if (!Update.begin(firmwareSize)) { - ESP_LOGE(TAG, "Firmware: Not enough space for update"); - updateProgress(UpdateStatus::MESSAGE, 0, "Firmware: Not enough space for update"); - http.end(); - return false; - } - - // Set up MD5 checking - MD5Builder md5; - md5.begin(); - - // Download and verify firmware - WiFiClient* stream = http.getStreamPtr(); - size_t remaining = firmwareSize; - while (remaining > 0) { - size_t chunk = std::min(remaining, size_t(BUFFER_SIZE)); - size_t read = stream->readBytes(downloadBuffer.get(), chunk); - - // Check for timeout - if (read == 0) { - ESP_LOGE(TAG, "Read timeout"); - - Update.abort(); - http.end(); - return false; - } - - // Update MD5 and write firmware - md5.add(downloadBuffer.get(), read); - if (Update.write(downloadBuffer.get(), read) != read) { - ESP_LOGE(TAG, "Write failed"); - Update.abort(); - http.end(); - return false; - } - - remaining -= read; - updateProgress(UpdateStatus::DOWNLOADING, (firmwareSize - remaining) * 100 / firmwareSize, "firmware"); - } - - // Verify MD5 - md5.calculate(); - String calculatedMd5 = md5.toString(); - if (!calculatedMd5.equals(expectedMd5)) { - ESP_LOGE(TAG, "MD5 mismatch. Expected: %s, Got: %s", expectedMd5, calculatedMd5.c_str()); - updateProgress(UpdateStatus::MESSAGE, 0, "Firmware: MD5 mismatch"); - Update.abort(); - http.end(); - return false; - } - - // Finish update - if (!Update.end()) { - ESP_LOGE(TAG, "Update end failed"); - updateProgress(UpdateStatus::MESSAGE, 0, "Firmware: Update failed"); - http.end(); - return false; - } - - http.end(); - return true; -} - -bool AppUpdater::IsUpdateAvailable(){ - return updateAvailable; -} - - - -//AsyncEventSource* eventSource = nullptr; -AsyncWebSocket* wsSource = nullptr; - -void startFirmwareUpdateTask(AsyncWebSocket* wsSrc) { - wsSource = wsSrc; - if(Update_Task_Handle) { - ESP_LOGW(TAG, "Firmware update task already running"); - return; - } - xTaskCreate(firmwareUpdateTask, "FirmwareUpdate", 8192, NULL, 1, &Update_Task_Handle); -} - -void firmwareUpdateTask(void* parameter) { - static const char* TAG = "UpdateTask"; - String updateJsonPath = "/system/update.json"; - AppUpdater* updater = nullptr; - - try { - // Read and parse update.json - File file = LittleFS.open(updateJsonPath); - if (!file) { - throw std::runtime_error("Failed to open update.json"); - } - - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - - if (error) { throw std::runtime_error("Failed to parse update.json"); } - - // Get update configuration - JsonObject jObj = doc.as(); - String baseUrl = jsonConstrainString(TAG, jObj, "baseurl", "https://storage.googleapis.com/boothifier/"); - String folderName = jsonConstrainString(TAG, jObj, "folder", "latest/"); - String url = baseUrl + folderName; - - // Initialize updater - updater = new AppUpdater(LittleFS, FIRMWARE_VERSION, url.c_str(), "update.json", "firmware.bin"); - updater->setProgressCallback(updateProgress); - - ESP_LOGI(TAG, "Starting update check from: %s", url.c_str()); - - - // Test loop - for(int i = 0; i < 10; i++) { - updateProgress(AppUpdater::UpdateStatus::MESSAGE, i * 10, "test"); - vTaskDelay(2000); - } - updateProgress(AppUpdater::UpdateStatus::MESSAGE, 100, "test complete"); - goto end; - - // Check and perform updates - if (!updater->checkManifest()) { throw std::runtime_error("Failed to check manifest"); } - - if (updater->IsUpdateAvailable()) { - ESP_LOGI(TAG, "Update available, updating files..."); - - if (!updater->updateFilesArray()) { throw std::runtime_error("Failed to update files"); } - - ESP_LOGI(TAG, "Updating firmware..."); - if (!updater->updateApp()) { throw std::runtime_error("Failed to update firmware"); } - - ESP_LOGI(TAG, "Update successful, restarting..."); - delete updater; - vTaskDelay(2000); - ESP.restart(); - } - - } catch (const std::exception& e) { - ESP_LOGE(TAG, "Update failed: %s", e.what()); - } - end: - delete updater; - Update_Task_Handle = NULL; - vTaskDelete(NULL); -} - -void updateProgress(AppUpdater::UpdateStatus newStatus, int percentage, const char* message = nullptr) { - - char buffer[128]; - const char* msg; - bool isComplete = false; - - switch (newStatus) { - case AppUpdater::UpdateStatus::IDLE: - snprintf(buffer, sizeof(buffer), "Update idle"); - msg = buffer; - break; - case AppUpdater::UpdateStatus::MESSAGE: - msg = message ? message : ""; - break; - case AppUpdater::UpdateStatus::DOWNLOADING: - snprintf(buffer, sizeof(buffer), "%s: Download progress: %d%%", message, percentage); - msg = buffer; - break; - case AppUpdater::UpdateStatus::VERIFYING: - snprintf(buffer, sizeof(buffer), "%s: Verifying update: %d%%", message, percentage); - msg = buffer; - break; - case AppUpdater::UpdateStatus::SKIPPING: - snprintf(buffer, sizeof(buffer), "%s: Skipping file update: already up to date", message); - msg = buffer; - break; - case AppUpdater::UpdateStatus::SAVING: - snprintf(buffer, sizeof(buffer), "%s: Saving update: %d%%", message, percentage); - msg = buffer; - break; - case AppUpdater::UpdateStatus::COMPLETE: - snprintf(buffer, sizeof(buffer), "%s: Update complete", message); - msg = buffer; - isComplete = true; - break; - case AppUpdater::UpdateStatus::ERROR: - snprintf(buffer, sizeof(buffer), "%s: Update error occurred", message); - msg = buffer; - break; - default: - snprintf(buffer, sizeof(buffer), "Unknown update status: %d", (int)newStatus); - msg = buffer; - break; - } - - ESP_LOGI(TAG, "%s", msg); - sendUpdateMessage(msg, isComplete, percentage); -} - -void sendUpdateMessage(const char* message, bool complete, int progress = -1) { - if(wsSource && wsSource->count() > 0) { - JsonDocument jsonDoc; - jsonDoc["message"] = message; - jsonDoc["complete"] = complete; - jsonDoc["progress"] = progress; - String strMessage; - serializeJson(jsonDoc, strMessage); - wsSource->textAll(strMessage); - } -} - - - - - - -/* -void setup() { - Serial.begin(115200); - - // Initialize WiFi connection first - // ... WiFi connection code ... - - // Initialize filesystem - if(!LittleFS.begin()) { - Serial.println("LittleFS Mount Failed"); - return; - } - - // Create updater instance with: - // - Current version: "1.0.0" - // - Update server URL: "https://my-update-server.com/" - // - Filesystem: LittleFS - AppUpdater updater("1.0.0", "https://storage.googleapis.com/boothifier/latest/", LittleFS); - - // Set progress callback - updater.setProgressCallback([](int progress) { - Serial.printf("Update progress: %d%%\n", progress); - }); - - // Check and update firmware - if (updater.checkAndUpdate()) { - Serial.println("Update successful! Rebooting..."); - ESP.restart(); - } - - // Update specific files from manifest - int updatedFiles = updater.updateFilesFromManifest("test_update.json"); - Serial.printf("Updated %d files\n", updatedFiles); -} - -*/ \ No newline at end of file diff --git a/webSock/AppUpgrade.h b/webSock/AppUpgrade.h deleted file mode 100644 index c23d9c0..0000000 --- a/webSock/AppUpgrade.h +++ /dev/null @@ -1,156 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include "AppVersion.h" - -#define DEFAULT_MANIFEST_URL "https://storage.googleapis.com/boothifier/latest/" -#define BUFFER_SIZE 4096 - -extern TaskHandle_t Update_Task_Handle; - -/** - * @brief File information structure - */ -struct FileInfo { - String remotePath; ///< Path on remote server - String localPath; ///< Path in local filesystem - String md5; ///< MD5 hash for verification - //size_t size; ///< File size in bytes -}; - -/** - * @class AppUpdater - * @brief Handles firmware and filesystem updates - */ -class AppUpdater { - public: - Version localVersion; - const char* bucketUrl; - const char* appName; - const char* manifestName; - JsonDocument jsonManifest; - JsonArray jsonFilesArray; - - /** - * @brief Update status enumeration - */ - enum class UpdateStatus { - IDLE, ///< No update in progress - MESSAGE, ///< Update message - DOWNLOADING, ///< Downloading files - VERIFYING, ///< Verifying file integrity - SKIPPING, ///< File already up to date - SAVING, ///< Saving to filesystem - COMPLETE, ///< Update complete - ERROR ///< Error occurred - }; - - /** - * @brief Constructor - * @param version Current firmware version - * @param bucket Base URL for updates - * @param fs Filesystem reference - */ - AppUpdater(fs::FS& fs, const char* currVersion, const char* bucket, const char* manifestName ="update.json", const char* appBin = "firmware.bin" ); - - /** - * @brief Set progress callback function - * @param callback Function to call with progress updates - */ - void setProgressCallback(void (*callback)( UpdateStatus status, int percentage, const char* message)); - - /** - * @brief Check for and apply updates - * @return true if update successful - */ - bool IsUpdateAvailable(void); - - /** - * @brief Update files from manifest - * @param manifestPath Path to manifest file - * @return true if all files updated successfully - */ - //bool updateFilesFromManifest(const char* manifestPath = DEFAULT_MANIFEST_URL); - bool updateFilesArray(void); - - /** - * @brief Update single file - * @param remotePath Remote file path - * @param localPath Local file path - * @param expectedMd5 Expected MD5 hash - * @return true if file updated successfully - */ - bool updateFile(const char* remotePath, const char* localPath, const char* expectedMd5); - - /** - * @brief Get manifest content - * @param manifestPath Path to manifest file - * @return Manifest content as a json document - */ - bool checkManifest(void); - - bool updateApp(void); - - String getVersion(void); - - private: - typedef void (*ProgressCallback)(UpdateStatus status, int percentage, const char* message); - ProgressCallback progressCb; - fs::FS& fileSystem; - UpdateStatus status; - std::unique_ptr downloadBuffer; - bool updateAvailable = false; - - - - /** - * @brief Verify and save file - * @param stream Input stream - * @param contentLength Expected content length - * @param localPath Local file path - * @param expectedMd5 Expected MD5 hash - * @return true if successful - */ - bool verifyAndSaveFile(WiFiClient* stream, size_t contentLength, - const char* localPath, const char* expectedMd5); - - /** - * @brief Update progress callback - * @param percentage Progress percentage - * @param newStatus Current status - */ - void updateProgress(UpdateStatus newStatus, int percentage, const char* message = nullptr); - - String getLocalMD5(const char* filePath); -}; - - - -// Queue handle for firmware update messages -extern QueueHandle_t updateMsgQueue; - -// Message structure for update progress -struct UpdateMessage { - String message; - bool complete; - int progress; -}; - -/** - * @brief Firmware update task - * @param param Task parameters - */ -void firmwareUpdateTask(void* param); - -void startFirmwareUpdateTask(AsyncWebSocket* eventSrc); - -void updateProgress(AppUpdater::UpdateStatus status, int percentage, const char* message); - -void sendUpdateMessage(const char* message, bool complete, int progress); - -void handleUpdateProgress(AsyncWebServerRequest *request); \ No newline at end of file diff --git a/webSock/my_wifi.cpp b/webSock/my_wifi.cpp deleted file mode 100644 index 45e53e4..0000000 --- a/webSock/my_wifi.cpp +++ /dev/null @@ -1,1164 +0,0 @@ -#include "my_wifi.h" -#include -#include -#include -#include -#include -#include "esp_log.h" -#include -#include -#include -#include "common/fileSystem.h" -#include "global.h" -#include "my_buzzer.h" -#include -#include -#include "jsonconstrain.h" -#include "AppUpgrade.h" - -static const char *tag = "WIFI"; - -volatile bool WifiClientConnected = false; -AsyncWebServer webServer(80); -AsyncWebSocket wsUpgradeProgress("/upgrade-progress"); -//AsyncEventSource eventUpgradeProgress("/upgrade-progress"); -//DNSServer *dnsServer; -//#define DNS_PORT 53 - -String client_ssid; -String client_pass; -String ap_ssid; -String ap_pass; - -String mDnsName; -String HostName; - -IPAddress local_IP(192,168,10,1); -IPAddress gateway(192,168,10,1); -IPAddress subnet(255,255,255,0); - -// for file manager page -String filesDropdownOptions((char*)0); -String dirDropdownOptions((char*)0); -String savePath((char*)0); // needed for storing file when editing a file -String savePathInput((char*)0); -const char* http_username = "admin"; -const char* http_password = "admin"; -const char* param_delete_path = "delete-path"; -const char* param_edit_path = "edit-path"; -const char* param_dir_pad = "dir-path"; -const char* param_edit_textarea = "edit-textarea"; -const char* param_save_path = "save-path"; -String allowedExtensionsForEdit = "txt, h, htm, html, css, cpp, js, json, ini, cfg"; - -volatile bool scanInProgress = false; - -static String networkList = ""; -int networkCount = 0; - -volatile int scanStatus = 0; // 0=none, 1=scanning, 2=complete, -1=error -String scanResults = ""; // Store scan results globally - -TaskHandle_t Wifi_Task_Handle; - -void Wifi_Task(void* parameter) { - - for(;;) { - static String last_ssid = ""; - - if (!WifiClientConnected || last_ssid != client_ssid) { - WifiClientConnected = false; - ESP_LOGD(tag, "Wifi trying to connect to: %s", client_ssid.c_str()); - WiFi.disconnect(); - vTaskDelay(1000); - WiFi.setAutoReconnect(false); - WiFi.begin(client_ssid.c_str(), client_pass.c_str()); - vTaskDelay(1000); - // wait up to 10 iterations for connection - int attempts = 0; - while (WiFi.status() != WL_CONNECTED && attempts < 10) { - wl_status_t status = WiFi.status(); - switch (status) { - case WL_NO_SSID_AVAIL: - ESP_LOGW(tag, "No AP with SSID %s found", client_ssid.c_str()); - break; - case WL_CONNECT_FAILED: - ESP_LOGW(tag, "Connection failed (wrong password?)"); - break; - case WL_DISCONNECTED: - ESP_LOGD(tag, "Not connected yet... (attempt %d/10)", attempts + 1); - break; - default: - ESP_LOGD(tag, "Status: %d", status); - break; - } - vTaskDelay(2000); - attempts++; - } - - if(WiFi.status() == WL_CONNECTED){ - ESP_LOGD(tag, "Connected to %s", client_ssid.c_str()); - //mDnsName = WiFi.hostname(); - WifiClientConnected = true; - WiFi.setAutoReconnect(true); - last_ssid = client_ssid; - // Save the WiFi settings - Wifi_Save_Credentials("/system/wifi.json"); - } else { - ESP_LOGW(tag, "Failed to connect to %s", client_ssid.c_str()); - } - } - - vTaskSuspend(Wifi_Task_Handle); - } - - vTaskDelete(NULL); -} - -void Wifi_Save_Credentials(String path) { - // Load existing JSON - JsonDocument doc; - File readFile = LittleFS.open(path, "r"); - if (readFile) { - DeserializationError error = deserializeJson(doc, readFile); - readFile.close(); - if (error) { - ESP_LOGE(tag, "Failed to parse existing JSON"); - return; - } - } - - // Update or create wifi-client section - JsonObject wifiClient = doc["wifi-client"].to(); - wifiClient["ssid"] = client_ssid; - wifiClient["pass"] = client_pass; - - // Save updated JSON - File writeFile = LittleFS.open(path, "w"); - if (!writeFile) { - ESP_LOGE(tag, "Error opening %s for writing", path.c_str()); - return; - } - - // Serialize JSON with pretty formatting - if (serializeJsonPretty(doc, writeFile) == 0) { - ESP_LOGE(tag, "Failed to write JSON to file"); - } - writeFile.close(); -} - -void Wifi_Init() { - // Initialize LittleFS - if (!LittleFS.begin(true)) { - ESP_LOGE(tag, "LittleFS mount failed"); - return; - } - - // Set Wi-Fi task to run on Core 1 - esp_wifi_set_ps(WIFI_PS_NONE); // Disable power save mode for better responsiveness - - // Set WiFi to AP+STA mode - WiFi.mode(WIFI_MODE_APSTA); - - Wifi_Scan_for_Networks(); - - // Configure and start AP - WiFi.softAPConfig(local_IP, gateway, subnet); - if (!WiFi.softAP(ap_ssid, ap_pass)) { - ESP_LOGE(tag, "AP start failed"); - return; - } - - // Add CORS headers - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*"); - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods", "GET, POST, PUT"); - DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Content-Type"); - - Setup_WebServer_Handlers(webServer); - - WiFi.onEvent(onWiFiEvent); - WiFi.setHostname(mDnsName.c_str()); - - webServer.begin(); - ESP_LOGD(tag, "AP started with IP: %s", WiFi.softAPIP().toString().c_str()); - - // Start the WiFi task - xTaskCreatePinnedToCore(Wifi_Task, "Wifi_Task", 1024*6, NULL, 1, &Wifi_Task_Handle, 0); -} - -void Wifi_Load_Settings(String path){ - // Load WiFi settings - File file = LittleFS.open(path, "r"); - if (!file) { - ESP_LOGE(tag, "Error opening %s", path.c_str()); - return; - } - - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - - if (error) { - ESP_LOGE(tag, "Failed to deserialize %s", path.c_str()); - return; - } - - JsonObject wifiJson = doc.as(); - if (wifiJson.isNull()) { - ESP_LOGE(tag, "%s is empty", path.c_str()); - return; - } - - // Load AP settings - JsonObject apJson = wifiJson["wifi-ap"]; - if (!apJson.isNull()) { - ap_ssid = jsonConstrainString(tag, apJson, "ssid", "ATA-AP"); - ap_pass = jsonConstrainString(tag, apJson, "pass", "12345678"); - local_IP.fromString(jsonConstrainString(tag, apJson, "ip", "192.168.10.1")); - gateway.fromString(jsonConstrainString(tag, apJson, "gateway", "192.168.10.1")); - subnet.fromString(jsonConstrainString(tag, apJson, "subnet", "255.255.255.0")); - } - - // Load Client settings - JsonObject clientJson = wifiJson["wifi-client"]; - if (!apJson.isNull()) { - client_ssid = jsonConstrainString(tag, clientJson, "ssid", "none"); - client_pass = jsonConstrainString(tag, clientJson, "pass", "12345678"); - } -} - -void Wifi_Scan_for_Networks(){ - // Start a scan for available networks - WiFi.scanNetworks(false, false); - while (WiFi.scanComplete() == WIFI_SCAN_RUNNING) { - vTaskDelay(100); // Wait for scan to complete - } - - networkCount = WiFi.scanComplete(); - if (networkCount >= 0) { - JsonDocument doc; - JsonArray networks = doc["networks"].to(); - - for (int i = 0; i < networkCount; i++) { - auto network = networks.add(); - network["ssid"] = WiFi.SSID(i); - network["rssi"] = WiFi.RSSI(i); - network["encryption"] = WiFi.encryptionType(i) != WIFI_AUTH_OPEN; - } - - String jsonString; - serializeJson(doc, jsonString); - networkList = jsonString; - WiFi.scanDelete(); - } else { - ESP_LOGE(tag, "WiFi scan failed"); - } -} - -void Setup_WebServer_Handlers(AsyncWebServer& server){ - - server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ - request->send(LittleFS, "/www/index.html", "text/html"); - }); - server.on("/home", HTTP_GET, [](AsyncWebServerRequest *request){ - sendHtmlFile("/www/home.html", request, HomeHtmlProcessor); - }); - server.on("/setup", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - //sendHtmlFile("/www/setup.html", request, htmlProcessor); - }); - server.on("/about", HTTP_GET, [](AsyncWebServerRequest *request){ - sendHtmlFile("/www/about.html", request, fileManagerHtmlProcessor); - //request->send(LittleFS, "/www/about.html", "text/html"); - }); - - - // Wifi related handlers - server.on("/wifi/connect", HTTP_POST, [](AsyncWebServerRequest *request){ - if (request->hasParam("ssid", false, false) && request->hasParam("pass", false, false)) { - client_ssid = request->getParam("ssid", false, false)->value().c_str(); - if (Wifi_Task_Handle != NULL && eTaskGetState(Wifi_Task_Handle) == eSuspended) { - ESP_LOGD(tag, "Resuming WiFi task"); - WifiClientConnected = false; - vTaskResume(Wifi_Task_Handle); - } else { - ESP_LOGE(tag, "Failed to resume WiFi task: invalid handle or task not suspended"); - } - vTaskResume(Wifi_Task_Handle); - request->send(200, "application/json", "{\"status\":\"connecting\"}"); - } else { - ESP_LOGE(tag, "Missing ssid or pass parameter"); - request->send(400, "application/json", "{\"error\":\"Missing ssid or pass parameter\"}"); - } - }); - server.on("/wifi/status", HTTP_GET, [](AsyncWebServerRequest *request){ - String jsonStr = "{\"status\":\"" + String(WifiClientConnected ? "Connected" : "Disconnected") + - "\",\"ip\":\"" + WiFi.localIP().toString() + "\"}"; - request->send(200, "application/json", jsonStr); - }); - server.on("/wifi/scans", HTTP_GET, [](AsyncWebServerRequest *request){ - if(networkCount <= 0) { - request->send(400, "application/json", "{\"error\":\"No scan results\"}"); - return; - } - - request->send(200, "application/json", networkList); - }); - server.on("/wifi", HTTP_GET, [](AsyncWebServerRequest *request){ - if(WiFi.getMode() == WIFI_MODE_APSTA){ - // TODO Disable navigation bar - } - //sendHtmlFile("/www/wifi.html", request, htmlProcessor); - request->send(LittleFS, "/www/wifi.html", "text/html"); - }); - - - // File Manager related handlers - server.on("/files/upload", HTTP_POST, [](AsyncWebServerRequest *request) { request->send(200); }, handleFilesUpload_OnBody); - - server.on("/files/download", HTTP_GET, [](AsyncWebServerRequest *request){ - if (!request->hasParam("file")) { - ESP_LOGE(tag, "Missing file parameter"); - request->send(400, "text/plain", "Missing file parameter"); - return; - } - - try { - String filename = uriDecode(request->getParam("file")->value()); - ESP_LOGD(tag, "Download request for: %s", filename.c_str()); - request->send(LittleFS, filename, "application/octet-stream"); - } - catch (const std::exception& e) { - ESP_LOGE(tag, "Download failed: %s", e.what()); - request->send(404, "text/plain", "File not found!"); - } - }); - server.on("/files/delete", HTTP_GET, [](AsyncWebServerRequest *request) { - static const char* tag = "DeleteHandler"; - - // Authentication check - if (!request->authenticate(http_username, http_password)) { - ESP_LOGW(tag, "Authentication failed for delete request"); - return request->requestAuthentication(); - } - - // Parameter validation - if (!request->hasParam(param_delete_path)) { - ESP_LOGE(tag, "Missing delete path parameter"); - request->send(400, "text/plain", "Missing file path"); - return; - } - - // Get and validate filename - String filename = uriDecode(request->getParam(param_delete_path)->value()); - if (filename == "choose") { - request->redirect("/files"); - return; - } - - // Ensure path starts with / - if (!filename.startsWith("/")) { - filename = "/" + filename; - } - - try { - if (LittleFS.remove(filename.c_str())) { - ESP_LOGI(tag, "Successfully deleted file: %s", filename.c_str()); - } else { - ESP_LOGE(tag, "Failed to delete file: %s", filename.c_str()); - request->send(500, "text/plain", "Delete failed"); - return; - } - } catch (const std::exception& e) { - ESP_LOGE(tag, "Exception during delete: %s", e.what()); - request->send(500, "text/plain", "Delete failed"); - return; - } - - request->redirect("/files"); - }); - server.on("/files/edit", HTTP_GET, [](AsyncWebServerRequest *request) { - static const char* tag = "EditHandler"; - - // Authentication check - if (!request->authenticate(http_username, http_password)) { - ESP_LOGW(tag, "Authentication failed"); - return request->requestAuthentication(); - } - - // Parameter validation - if (!request->hasParam(param_edit_path)) { - ESP_LOGE(tag, "Missing edit path parameter"); - request->send(400, "text/plain", "Missing file path"); - return; - } - - // Get and decode filename - String fileName = uriDecode(request->getParam(param_edit_path)->value()); - ESP_LOGD(tag, "Edit request for file: %s", fileName.c_str()); - - // Set save path - savePath = (fileName == "new") ? "/new.txt" : fileName; - - // Validate path - if (!savePath.startsWith("/")) { - savePath = "/" + savePath; - } - - ESP_LOGD(tag, "Save path set to: %s", savePath.c_str()); - - try { - sendHtmlFile("/www/edit.html", request, fileManagerHtmlProcessor); - } catch (const std::exception& e) { - ESP_LOGE(tag, "Failed to send edit page: %s", e.what()); - request->send(500, "text/plain", "Internal server error"); - } - }); - server.on("/files/save", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - String inputMessage((char*)0); - if (request->hasParam(param_edit_textarea)) { - inputMessage = request->getParam(param_edit_textarea)->value(); - } - if (request->hasParam(param_save_path)) { - savePath = uriDecode(request->getParam(param_save_path)->value()); - } - writeFile(LittleFS, savePath.c_str(), inputMessage.c_str()); - - request->redirect("/files"); - }); - server.on("/files", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - sendHtmlFile("/www/files.html", request, fileManagerHtmlProcessor); - }); - - - // Lights related handlers - server.on("/lights/settings", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200); - }); - server.on("/lights/settings", HTTP_POST, [](AsyncWebServerRequest *request) { - request->send(200); - }); - server.on("/lights/animation", HTTP_POST, [](AsyncWebServerRequest *request) { - request->send(200); - }); - server.on("/lights/setpixel", HTTP_POST, [](AsyncWebServerRequest *request) { - request->send(200); - }); - - - // System and LED related handlers - server.on("/system/summary", HTTP_GET, [](AsyncWebServerRequest *request){ - String response = "{\"status\":\"" + String(WifiClientConnected ? "Connected" : "Disconnected") + "\"}"; - request->send(200, "application/json", response); - }); - server.on("/leds/settings", HTTP_GET, [](AsyncWebServerRequest *request){ - /* - //CreateSysSummmaryPacket(doc); - String summary; - serializeJson(jsDoc, summary); - request->send(200, "application/json", summary); - */ - String response = "{\"status\":\"" + String(WifiClientConnected ? "Connected" : "Disconnected") + "\"}"; - request->send(200, "application/json", response); - }); - server.on("/leds/settings", HTTP_POST, [](AsyncWebServerRequest *request){ - String response = "{\"status\":\"" + String(WifiClientConnected ? "Connected" : "Disconnected") + "\"}"; - request->send(200, "application/json", response); - }); - - - - // LightStik related handlers - server.on("/lightstik/settings", HTTP_GET, [](AsyncWebServerRequest *request){ - String response = "{\"status\":\"" + String(WifiClientConnected ? "Connected" : "Disconnected") + "\"}"; - request->send(200, "application/json", response); - }); - server.on("/lightstik/settings", HTTP_POST, [](AsyncWebServerRequest *request){ - String response = "{\"status\":\"" + String(WifiClientConnected ? "Connected" : "Disconnected") + "\"}"; - request->send(200, "application/json", response); - }); - server.on("/lightstik/register", HTTP_POST, [](AsyncWebServerRequest *request){ - String response = "{\"status\":\"" + String(WifiClientConnected ? "Connected" : "Disconnected") + "\"}"; - request->send(200, "application/json", response); - }); - - - // Firmware Update Handlers - server.on("/upgrade/check", HTTP_GET, [](AsyncWebServerRequest *request) { - JsonDocument doc; - doc["currentVersion"] = FIRMWARE_VERSION; - doc["latestVersion"] = "1.1.0"; - doc["updateAvailable"] = true; - - String response; - serializeJson(doc, response); - request->send(200, "application/json", response); - }); - // Start update process - server.on("/upgrade/start", HTTP_POST, [](AsyncWebServerRequest *request) { - //if (!request->authenticate(http_username, http_password)) { - // return request->requestAuthentication(); - //} - startFirmwareUpdateTask(&wsUpgradeProgress); - request->send(200); - }); - //server.on("/upgrade/progress", HTTP_GET, [](AsyncWebServerRequest *request) { - /* - if (!request->authenticate(http_username, http_password)) { - return request->requestAuthentication(); - } - AsyncWebServerResponse *response = request->beginResponse(200, "text/event-stream"); - response->addHeader("Cache-Control", "no-cache"); - response->addHeader("Connection", "keep-alive"); - request->send(response); - */ - //}); - server.on("/upgrade", HTTP_GET, [](AsyncWebServerRequest *request) { - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - request->send(LittleFS, "/www/upgrade.html", "text/html"); - }); - - wsUpgradeProgress.onEvent(onWsUpdateProgressEvent); - server.addHandler(&wsUpgradeProgress); - - // Basic Connection status check - server.on("/api/status", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "application/json", "{\"status\":\"connected\"}"); - }); - // Server requested files that aren't template processed - server.on("/*", HTTP_GET, [](AsyncWebServerRequest *request) { // handle file uploads - // Validate request - if (!request) { - ESP_LOGE(tag, "Invalid request"); - return; - } - - // Get and validate file path - String filePath = request->url(); - if (filePath.isEmpty()) { - ESP_LOGE(tag, "Empty file path"); - request->send(400, "text/plain", "Invalid file path"); - return; - } - - // Ensure path starts with '/' - if (!filePath.startsWith("/")) { - filePath = "/" + filePath; - } - - try { - // Get content type once - const char* contentType = getFileType(getFileExtension(filePath.c_str())); - if (!contentType) { - ESP_LOGW(tag, "Unknown file type: %s", filePath.c_str()); - contentType = "application/octet-stream"; - } - - ESP_LOGD(tag, "Sending file: %s (%s)", filePath.c_str(), contentType); - request->send(LittleFS, filePath, contentType); - } - catch (const std::runtime_error& e) { - ESP_LOGE(tag, "FileSystem error: %s for path: %s", e.what(), filePath.c_str()); - request->send(404, "text/plain", "File not found"); - } - catch (const std::exception& e) { - ESP_LOGE(tag, "Error: %s for path: %s", e.what(), filePath.c_str()); - request->send(500, "text/plain", "Internal server error"); - } - }); - // 404 handler - server.onNotFound([](AsyncWebServerRequest *request) { - ESP_LOGE(tag, "404: %s", request->url().c_str()); - request->send(404, "text/plain", "Not found"); - }); - -} - -void onWsUpdateProgressEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { - switch (type) { - case WS_EVT_CONNECT: - ESP_LOGD(tag,"WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); - break; - case WS_EVT_DISCONNECT: - ESP_LOGD(tag, "WebSocket client #%u disconnected\n", client->id()); - break; - case WS_EVT_DATA: - ESP_LOGD(tag, "WebSocket client #%u data\n", client->id()); - //handleWebSocketMessage(arg, data, len); - break; - case WS_EVT_PONG: - ESP_LOGD(tag, "WebSocket client #%u pong\n", client->id()); - break; - case WS_EVT_ERROR: - ESP_LOGD(tag, "WebSocket client #%u error\n", client->id()); - break; - } -} - - - -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 * 1024; // 1MB limit - - if (!index) { - // Initial upload chunk - 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 path = p->value() + "/" + filename; - ESP_LOGD(tag, "Starting upload: %s", path.c_str()); - - // Validate path - if (!path.startsWith("/")) { - path = "/" + path; - } - - 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; - } - } - - // Write chunk - if (len && request->_tempFile) { - if (index + len > MAX_UPLOAD_SIZE) { - request->_tempFile.close(); - LittleFS.remove(request->_tempFile.name()); - ESP_LOGE(tag, "Upload too large"); - request->send(413, "text/plain", "File too large"); - return; - } - - if (!request->_tempFile.write(data, len)) { - ESP_LOGE(tag, "Write failed"); - request->_tempFile.close(); - request->send(500, "text/plain", "Write failed"); - return; - } - } - - if (final) { - request->_tempFile.close(); - ESP_LOGD(tag, "Upload complete: %s, %u bytes", filename.c_str(), index + len); - request->redirect("/files"); - } -} - - -// Send html file with template processing {{VAR}} -void sendHtmlFile(const char* filePath, AsyncWebServerRequest *request, String (*callback)(const String&)) { - try { - const char* htmlFile = readFile(LittleFS, filePath); - if (!htmlFile) { - ESP_LOGE(tag, "Failed to read file: %s", filePath); - request->send(404, "text/plain", "File not found"); - return; - } - - String processedData = varReplace(htmlFile, callback); - delete[] htmlFile; // Clean up allocated memory - - ESP_LOGD(tag, "Sent file: %s", filePath); - request->send(200, "text/html", processedData); - } - catch (const std::exception& e) { - ESP_LOGE(tag, "Error processing file %s: %s", filePath, e.what()); - request->send(500, "text/plain", "Server error"); - } -} - -const char* getFileExtension(const char* filename) { - // Input validation - if (!filename) { - ESP_LOGW(tag, "Null filename provided"); - return ""; - } - - // Find last dot - const char* lastDot = strrchr(filename, '.'); - if (!lastDot || lastDot == filename || *(lastDot + 1) == '\0') { - ESP_LOGD(tag, "No valid extension found in: %s", filename); - return ""; - } - - ESP_LOGD(tag, "Found extension: %s", lastDot + 1); - return lastDot + 1; -} - -const char* getFileType(const char* ext) { - if (!ext) return "application/octet-stream"; - - ESP_LOGD(tag, "Getting file type for extension: %s", ext); - - if (strcmp(ext, "png") == 0) return "image/png"; - if (strcmp(ext, "jpg") == 0 || strcmp(ext, "jpeg") == 0) return "image/jpeg"; - if (strcmp(ext, "gif") == 0) return "image/gif"; - if (strcmp(ext, "ico") == 0) return "image/x-icon"; - if (strcmp(ext, "txt") == 0) return "text/plain"; - if (strcmp(ext, "css") == 0) return "text/css"; - if (strcmp(ext, "htm") == 0 || strcmp(ext, "html") == 0) return "text/html"; - if (strcmp(ext, "js") == 0) return "text/javascript"; - if (strcmp(ext, "json") == 0) return "application/json"; - - ESP_LOGW(tag, "Unknown file extension: %s", ext); - return "application/octet-stream"; -} - -// Finds segments between {{VAR}} and calls a callback function to replace VAR with new content -String varReplace(const String& input, String (*callback)(const String&)) { - static const char* tag = "varReplace"; - - // Validate inputs - if (input.isEmpty() || !callback) { - ESP_LOGW(tag, "Empty input or null callback"); - return input; - } - - // Pre-allocate result string with estimated size - String result; - result.reserve(input.length() * 1.2); // Add 20% for potential replacements - - const int maxSegmentLength = 32; - int startPos = 0; - - // Process all segments - while (true) { - // Find next variable - int start = input.indexOf("{{", startPos); - if (start == -1) { - break; - } - - // Add text before variable - result += input.substring(startPos, start); - - // Find end of variable - int end = input.indexOf("}}", start + 2); - if (end == -1) { - ESP_LOGW(tag, "Unmatched {{ at position %d", start); - result += input.substring(start); - break; - } - - // Extract and validate segment - String segment = input.substring(start + 2, end); - if (segment.length() <= maxSegmentLength) { - try { - String replacement = callback(segment); - result += replacement; - } catch (const std::exception& e) { - ESP_LOGE(tag, "Callback error: %s", e.what()); - result += input.substring(start, end + 2); - } - } else { - ESP_LOGW(tag, "Segment too long: %d chars", segment.length()); - result += input.substring(start, end + 2); - } - - startPos = end + 2; - } - - // Add remaining text - if (startPos < input.length()) { - result += input.substring(startPos); - } - - return result; -} - -const char* convertFileSize(const size_t bytes) { - static char fileSizeBuffer[16]; // Pre-allocated buffer for the file size - - if (bytes < 1024) { - snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%d B", bytes); - } else if (bytes < 1024 * 1024) { - snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%.2f kB", bytes / 1024.0); - } else if (bytes < 1024 * 1024 * 1024) { - snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%.2f MB", bytes / (1024.0 * 1024.0)); - } else { - snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%.2f GB", bytes / (1024.0 * 1024.0 * 1024.0)); - } - - return fileSizeBuffer; -} - -void onWiFiEvent(WiFiEvent_t event) { - //Serial.printf("[WiFi-event] event: %d\n", event); - switch (event) { - case ARDUINO_EVENT_WIFI_READY: - ESP_LOGD(tag, "WiFi interface ready"); - break; - case ARDUINO_EVENT_WIFI_SCAN_DONE: - ESP_LOGD(tag,"Completed scan for access points"); - break; - case ARDUINO_EVENT_WIFI_STA_START: - ESP_LOGD(tag,"WiFi client started"); - break; - case ARDUINO_EVENT_WIFI_STA_STOP: - ESP_LOGD(tag,"WiFi clients stopped"); - break; - case ARDUINO_EVENT_WIFI_STA_CONNECTED: - ESP_LOGD(tag,"Connected to AP"); - break; - case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: - WifiClientConnected = false; - ESP_LOGD(tag, "WiFi Disconnected"); - Buzzer_Play_Tune(TUNE_DISCONNECTED); - break; - case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: - ESP_LOGD(tag,"Authentication mode of access point has changed"); - break; - case ARDUINO_EVENT_WIFI_STA_GOT_IP: - WifiClientConnected = true; - ESP_LOGD(tag,"My IP: %s", WiFi.localIP().toString()); - //Wifi_Start_MDNS(); - Buzzer_Play_Tune(TUNE_CONNECTED); - break; - case ARDUINO_EVENT_WIFI_STA_LOST_IP: - WifiClientConnected = false; - ESP_LOGD(tag,"Lost IP address and IP address is reset to 0"); - break; - case ARDUINO_EVENT_WPS_ER_SUCCESS: - ESP_LOGD(tag,"WiFi Protected Setup (WPS): succeeded in enrollee mode"); - break; - case ARDUINO_EVENT_WPS_ER_FAILED: - ESP_LOGD(tag,"WiFi Protected Setup (WPS): failed in enrollee mode"); - break; - case ARDUINO_EVENT_WPS_ER_TIMEOUT: - ESP_LOGD(tag,"WiFi Protected Setup (WPS): timeout in enrollee mode"); - break; - case ARDUINO_EVENT_WPS_ER_PIN: - ESP_LOGD(tag,"WiFi Protected Setup (WPS): pin code in enrollee mode"); - break; - case ARDUINO_EVENT_WIFI_AP_START: - ESP_LOGD(tag, "WiFi access point started"); - break; - case ARDUINO_EVENT_WIFI_AP_STOP: - ESP_LOGD(tag, "WiFi access point stopped"); - break; - case ARDUINO_EVENT_WIFI_AP_STACONNECTED: - ESP_LOGD(tag, "Client connected"); - break; - case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED: - ESP_LOGD(tag, "SoftAP Client Disconnected"); - Buzzer_Play_Tune(TUNE_DISCONNECTED); - break; - case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED: - ESP_LOGD(tag,"SoftAP Client Connected"); - Buzzer_Play_Tune(TUNE_CONNECTED); - break; - case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED: - ESP_LOGD(tag,"Received probe request"); - break; - case ARDUINO_EVENT_WIFI_AP_GOT_IP6: - ESP_LOGD(tag,"AP IPv6 is preferred"); - break; - case ARDUINO_EVENT_WIFI_STA_GOT_IP6: - ESP_LOGD(tag,"STA IPv6 is preferred"); - break; - case ARDUINO_EVENT_ETH_GOT_IP6: - ESP_LOGD(tag,"Ethernet IPv6 is preferred"); - break; - case ARDUINO_EVENT_ETH_START: - ESP_LOGD(tag,"Ethernet started"); - break; - case ARDUINO_EVENT_ETH_STOP: - ESP_LOGD(tag,"Ethernet stopped"); - break; - case ARDUINO_EVENT_ETH_CONNECTED: - ESP_LOGD(tag,"Ethernet connected"); - break; - case ARDUINO_EVENT_ETH_DISCONNECTED: - ESP_LOGD(tag,"Ethernet disconnected"); - break; - case ARDUINO_EVENT_ETH_GOT_IP: - ESP_LOGD(tag,"Obtained IP address"); - break; - default: break; - } -} - -void Wifi_Start_MDNS(void) { - ESP_LOGV(tag, "Initializing MDNS: %s", mDnsName.c_str()); - if (!MDNS.begin(mDnsName.c_str())) { - ESP_LOGE(tag, "Error setting up MDNS responder!"); - }else{ - ESP_LOGV(tag, "You can access device via http://%s.local", mDnsName); - } -} - -bool writeFile(fs::FS &fs, const char* path, const char* message) { - // Validate inputs - if (!path || !message) { - ESP_LOGE(tag, "Invalid parameters: path=%p message=%p", path, message); - return false; - } - - // Open file with error checking - File file = fs.open(path, "w"); - if (!file) { - ESP_LOGE(tag, "Failed to open file: %s", path); - return false; - } - - // Write with error handling - try { - size_t bytesWritten = file.print(message); - if (bytesWritten == 0) { - ESP_LOGE(tag, "Failed to write to file: %s", path); - file.close(); - return false; - } - - // Ensure all data is written - file.flush(); - file.close(); - ESP_LOGD(tag, "Successfully wrote %u bytes to %s", bytesWritten, path); - return true; - } - catch (const std::exception& e) { - ESP_LOGE(tag, "Exception while writing file %s: %s", path, e.what()); - file.close(); - return false; - } -} - -char* readFile(fs::FS &fs, const char* path) { - static const char* tag = "readFile"; - static const size_t MAX_FILE_SIZE = 1024 * 1024; // 1MB limit - - // Validate input - if (!path) { - ESP_LOGE(tag, "Invalid path parameter"); - return nullptr; - } - - // Open file - File file = fs.open(path, "r"); - if (!file || file.isDirectory()) { - ESP_LOGE(tag, "Failed to open file: %s", path); - return nullptr; - } - - // Check file size - size_t fileSize = file.size(); - if (fileSize == 0 || fileSize > MAX_FILE_SIZE) { - ESP_LOGE(tag, "Invalid file size: %u bytes", fileSize); - file.close(); - return nullptr; - } - - // Allocate memory - char* fileContent = new (std::nothrow) char[fileSize + 1]; - if (!fileContent) { - ESP_LOGE(tag, "Memory allocation failed for size: %u", fileSize + 1); - file.close(); - return nullptr; - } - - // Read file - size_t bytesRead = file.readBytes(fileContent, fileSize); - file.close(); - - if (bytesRead != fileSize) { - ESP_LOGE(tag, "Read failed: expected %u bytes, got %u", fileSize, bytesRead); - delete[] fileContent; - return nullptr; - } - - // Null terminate - fileContent[bytesRead] = '\0'; - ESP_LOGD(tag, "Successfully read %u bytes from %s", bytesRead, path); - return fileContent; -} - -String getSoftAPMacAddress() { - uint8_t mac[6]; - WiFi.softAPmacAddress(mac); - - String macString = ""; - for (int i = 0; i < 6; i++) { - macString += String(mac[i], HEX); - if (i < 5) macString += ":"; - } - return macString; -} - -String listDirAsHtml(String directoryList[], int count) { - String listedFiles; - - for (int i = 0; i < count; i++) { - // directory html - listedFiles += "Dir: "; - listedFiles += directoryList[i]; - listedFiles += "/-\n"; - - filesDropdownOptions += "\n"; - - dirDropdownOptions += "\n"; - - File dir = LittleFS.open(directoryList[i]); - File file = dir.openNextFile(); - while (file) { - String fileName = file.name(); - if (!file.isDirectory()) { - //Serial.println(" File: " + String(file.name())); - listedFiles += "  "; - listedFiles += fileName; - listedFiles += ""; - listedFiles += convertFileSize(file.size()); - listedFiles += "\n"; - - filesDropdownOptions += "\n"; - } - file = dir.openNextFile(); - } - dir.close(); - } - - return listedFiles; -} - - - -/******************** Specific Html Processors ********************/ -// file manager html processor -String fileManagerHtmlProcessor(const String& var){ - if(var == "ALLOWED_EXTENSIONS_EDIT"){ return allowedExtensionsForEdit; } - - if(var == "FS_FREE_BYTES"){ return convertFileSize(LittleFS.totalBytes() - LittleFS.usedBytes()); } - - if(var == "FS_USED_BYTES"){ return convertFileSize(LittleFS.usedBytes()); } - - if(var == "FS_TOTAL_BYTES"){ return convertFileSize(LittleFS.totalBytes()); } - - if(var == "RAM_FREE_BYTES"){ return convertFileSize(LittleFS.totalBytes()); } - - if(var == "RAM_USED_BYTES"){ return convertFileSize(LittleFS.totalBytes()); } - - if(var == "RAM_TOTAL_BYTES"){ return convertFileSize(LittleFS.totalBytes()); } - - if(var == "LISTED_FILES"){ - filesDropdownOptions = ""; // clear out - dirDropdownOptions = ""; // clear out - String directories[MAX_DIRECTORIES]; - int dirCount = 0; - getAllDirectories(directories, dirCount); - return listDirAsHtml(directories, dirCount); - } - - if(var == "EDIT-DEL_FILES"){ return filesDropdownOptions; } - - if(var == "DIR_LIST"){ return dirDropdownOptions; } - - if(var == "SAVE_PATH_INPUT"){ return savePath; } - - if(var == "FIRM_VER"){ return FIRMWARE_VERSION; } - - return var; -} - -String HomeHtmlProcessor(const String& var) { - if (var == "APP_NAME") { - //return sysProps.appName; - return "N/A"; - } - if (var == "OLED") { - return "N/A"; - } - if (var == "STRIP1") { - //return (strip1) ? "Yes" : "No"; - return "N/A"; - } - if (var == "STRIP2") { - //return (strip2) ? "Yes" : "No"; - return "N/A"; - } - if (var == "FRONT_LIGHT") { - //return (animProps.frontLight.enabled) ? "Yes" : "No"; - return "N/A"; - } - if (var == "REAR_LIGHT") { - //return (animProps.rearLight.enabled) ? "Yes" : "No"; - return "N/A"; - } - if (var == "FIRMWARE") { - return FIRMWARE_VERSION; - } - if (var == "BOOTH_T") { - //return String(sysProps.t_sensor.temperature) + "F"; - return "N/A"; - } - if (var == "SETPOINT") { - //return String(sysProps.t_sensor.Setpoint1) + "F"; - return "N/A"; - } - if (var == "FLASH_SIZE") { return convertFileSize(ESP.getSketchSize());} - if (var == "FLASH_FREE") { return convertFileSize(ESP.getFreeSketchSpace());} - if (var == "HEAP_SIZE") { return convertFileSize(ESP.getHeapSize()); } - if (var == "HEAP_FREE") { return convertFileSize(ESP.getFreeHeap()); } - if (var == "CPU_FREQ") { return String(ESP.getCpuFreqMHz()) + "Mhz"; } - if (var == "IP") { return WiFi.localIP().toString(); } - if (var == "MAC") { return chipInfo.macStr; } - if (var == "SSID") { return WiFi.SSID(); } - if (var == "RSSI") { return String(WiFi.RSSI()); } - if (var == "WIFI_CH") { return String(WiFi.channel()); } - if (var == "ENCRYP") { return String(WiFi.encryptionType(0)); } - if (var == "AP_SSID") { return WiFi.softAPSSID(); } - if (var == "AP_CLIENTS") { return String(WiFi.softAPgetStationNum()); } - if (var == "BLE") { return (commMode == COMM_WIFI_AP_BLE) ? "Yes" : "No"; } - if (var == "BLE_SSID") { - //return (commMode == COMM_WIFI_AP_BLE) ? BLEDeviceName : ""; - return "N/A"; - } - if (var == "BLE_CLIENTS") { - //return (BTDeviceConnected) ? "1" : "0"; - return "N/A"; - } - if (var == "AP_MAC") { return getSoftAPMacAddress(); } - - // Return an empty string if the variable is not recognized - return var; -} - - - -void handleUpdateProgress(AsyncWebServerRequest *request) { - static const char* tag = "UpdateProgress"; - - //if (!request->authenticate(http_username, http_password)) { - // return request->requestAuthentication(); - //} - - request->send(200, "text/plain", "Update progress"); // Send a simple response -} diff --git a/webSock/my_wifi.h b/webSock/my_wifi.h deleted file mode 100644 index 603d416..0000000 --- a/webSock/my_wifi.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -void Wifi_Init(void); -void Wifi_Load_Settings(String path); -void Wifi_Scan_for_Networks(void); -void Wifi_Start_MDNS(void); -void onWiFiEvent(WiFiEvent_t event); -void Wifi_Save_Credentials(String path); -void Setup_WebServer_Handlers(AsyncWebServer& serv); - -void handlePOST_Update(AsyncWebServerRequest *request); -void updateCallback(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); -void updateFirmwareProgress(size_t progress, size_t total); - -void handleGET_Query(AsyncWebServerRequest *request); - -void handleFilesUpload_OnBody(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); - -void sendHtmlFile(const char* filePath, AsyncWebServerRequest *request, String (*callback)(const String&)); -String fileManagerHtmlProcessor(const String& var); -String HomeHtmlProcessor(const String& var); -String listDirAsHtml(String directoryList[], int count); - -const char* getFileExtension(const char* filename); -const char* getFileType(const char* ext); -const char* convertFileSize(const size_t bytes); -bool writeFile(fs::FS &fs, const char *path, const char *message); -char* readFile(fs::FS &fs, const char *path); - -String varReplace(const String& input, String (*callback)(const String&)); -String getSoftAPMacAddress(void); - -void onWsUpdateProgressEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len); diff --git a/webSock/upgrade.html b/webSock/upgrade.html deleted file mode 100644 index c0b55ea..0000000 --- a/webSock/upgrade.html +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - Firmware Upgrade - - - - -
-

Firmware Upgrade

- -
- - Disconnected -
- -
-

Current Version: -

-

Latest Version: -

-
- -
- - -
- -
-
- - - - \ No newline at end of file diff --git a/z_old/HSVTable.cpp b/z_old/HSVTable.cpp deleted file mode 100644 index a5643e7..0000000 --- a/z_old/HSVTable.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#include "HSVTable.h" -#include -#include "LEDStrip.h" - - -const uint8_t lights[360]={ - 0, 0, 0, 0, 0, 1, 1, 2, - 2, 3, 4, 5, 6, 7, 8, 9, - 11, 12, 13, 15, 17, 18, 20, 22, - 24, 26, 28, 30, 32, 35, 37, 39, - 42, 44, 47, 49, 52, 55, 58, 60, - 63, 66, 69, 72, 75, 78, 81, 85, - 88, 91, 94, 97, 101, 104, 107, 111, -114, 117, 121, 124, 127, 131, 134, 137, -141, 144, 147, 150, 154, 157, 160, 163, -167, 170, 173, 176, 179, 182, 185, 188, -191, 194, 197, 200, 202, 205, 208, 210, -213, 215, 217, 220, 222, 224, 226, 229, -231, 232, 234, 236, 238, 239, 241, 242, -244, 245, 246, 248, 249, 250, 251, 251, -252, 253, 253, 254, 254, 255, 255, 255, -255, 255, 255, 255, 254, 254, 253, 253, -252, 251, 251, 250, 249, 248, 246, 245, -244, 242, 241, 239, 238, 236, 234, 232, -231, 229, 226, 224, 222, 220, 217, 215, -213, 210, 208, 205, 202, 200, 197, 194, -191, 188, 185, 182, 179, 176, 173, 170, -167, 163, 160, 157, 154, 150, 147, 144, -141, 137, 134, 131, 127, 124, 121, 117, -114, 111, 107, 104, 101, 97, 94, 91, - 88, 85, 81, 78, 75, 72, 69, 66, - 63, 60, 58, 55, 52, 49, 47, 44, - 42, 39, 37, 35, 32, 30, 28, 26, - 24, 22, 20, 18, 17, 15, 13, 12, - 11, 9, 8, 7, 6, 5, 4, 3, - 2, 2, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0}; - -const uint8_t HSVlights[61] = -{0, 4, 8, 13, 17, 21, 25, 30, 34, 38, 42, 47, 51, 55, 59, 64, 68, 72, 76, -81, 85, 89, 93, 98, 102, 106, 110, 115, 119, 123, 127, 132, 136, 140, 144, -149, 153, 157, 161, 166, 170, 174, 178, 183, 187, 191, 195, 200, 204, 208, -212, 217, 221, 225, 229, 234, 238, 242, 246, 251, 255}; - -const uint8_t HSVpower[121] = -{0, 2, 4, 6, 8, 11, 13, 15, 17, 19, 21, 23, 25, 28, 30, 32, 34, 36, 38, 40, -42, 45, 47, 49, 51, 53, 55, 57, 59, 62, 64, 66, 68, 70, 72, 74, 76, 79, 81, -83, 85, 87, 89, 91, 93, 96, 98, 100, 102, 104, 106, 108, 110, 113, 115, 117, -119, 121, 123, 125, 127, 130, 132, 134, 136, 138, 140, 142, 144, 147, 149, -151, 153, 155, 157, 159, 161, 164, 166, 168, 170, 172, 174, 176, 178, 181, -183, 185, 187, 189, 191, 193, 195, 198, 200, 202, 204, 206, 208, 210, 212, -215, 217, 219, 221, 223, 225, 227, 229, 232, 234, 236, 238, 240, 242, 244, -246, 249, 251, 253, 255}; - -// the real HSV rainbow -rgbpixel_t trueHSV(int angle) -{ - byte red, green, blue; - - if (angle<60) {red = 255; green = HSVlights[angle]; blue = 0;} else - if (angle<120) {red = HSVlights[120-angle]; green = 255; blue = 0;} else - if (angle<180) {red = 0, green = 255; blue = HSVlights[angle-120];} else - if (angle<240) {red = 0, green = HSVlights[240-angle]; blue = 255;} else - if (angle<300) {red = HSVlights[angle-240], green = 0; blue = 255;} else - {red = 255, green = 0; blue = HSVlights[360-angle];} - - //return {red, green, blue}; - return {red, green, blue}; -} - -// the 'power-conscious' HSV rainbow -rgbpixel_t powerHSV(int angle) -{ - byte red, green, blue; - if (angle<120) {red = HSVpower[120-angle]; green = HSVpower[angle]; blue = 0;} else - if (angle<240) {red = 0; green = HSVpower[240-angle]; blue = HSVpower[angle-120];} else - {red = HSVpower[angle-240]; green = 0; blue = HSVpower[360-angle];} - - return {red, green, blue}; -} - -// sine wave rainbow -rgbpixel_t sineHSV(int angle) -{ - return {lights[(angle+120)%360], lights[angle], lights[(angle+240)%360]}; -} - - -// hsv out: 0-360, input rgb 0-255 -float RGBToHSV(rgbpixel_t rgb) { - float delta; // min; - float h = 0, v; //, s; - - uint8_t min_ = std::min(std::min(rgb.red, rgb.grn), rgb.blu); - v = std::max(std::max(rgb.red, rgb.grn), rgb.blu); - delta = v - min_; - - if (rgb.red == v){ - h = (rgb.grn - rgb.blu) / delta; - }else if (rgb.grn == v){ - h = 2 + (rgb.blu - rgb.red) / delta; - }else if (rgb.blu == v){ - h = 4 + (rgb.red - rgb.grn) / delta; - } - - h *= 60; - - if(h < 0.0){ h = h + 360;} - if(h > 359.99){ h = 359.99;} - return isnan(h) ? 0.0 : h; -} - - -rgbpixel_t HSVToRGB(float H) { - float r = 0.0, g = 0.0, b = 0.0; - float S = 1.0; - float V = 1.0; - - if (H < 0) { H += 360; } - if (H > 359) { H -= 360; } - - if (S == 0.0) { - r = V; g = V; b = V; - }else { - int i; - float f, p, q, t; - - if (H == 360){ H = 0; } - else { H = H / 60; } - - i = (int)trunc(H); - f = H - i; - - p = V * (1.0 - S); - q = V * (1.0 - (S * f)); - t = V * (1.0 - (S * (1.0 - f))); - - switch (i) { - case 0: - r = V; g = t; b = p; break; - case 1: - r = q; g = V; b = p; break; - case 2: - r = p; g = V; b = t; break; - case 3: - r = p; g = q; b = V; break; - case 4: - r = t; g = p; b = V; break; - default: - r = V; g = p; b = q; break; - } - } - - rgbpixel_t pix; - pix.red = (uint8_t)(r * 255); - pix.grn = (uint8_t)(g * 255); - pix.blu = (uint8_t)(b * 255); - - return pix; -} - diff --git a/z_old/HSVTable.h b/z_old/HSVTable.h deleted file mode 100644 index f88957c..0000000 --- a/z_old/HSVTable.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef HSVTABLE_H -#define HSVTABLE_H - -#include "LEDStrip.h" - - -rgbpixel_t trueHSV(int angle); - -rgbpixel_t powerHSV(int angle); - -rgbpixel_t sineHSV(int angle); - -rgbpixel_t HSVToRGB(float H); - -// Returne a 0-360 float -float RGBToHSV(rgbpixel_t rgb); - -// Input 0-360 float - - - - -#endif \ No newline at end of file diff --git a/z_old/LEDStrip.cpp b/z_old/LEDStrip.cpp deleted file mode 100644 index dd54478..0000000 --- a/z_old/LEDStrip.cpp +++ /dev/null @@ -1,473 +0,0 @@ -#include "LEDStrip.h" -#include "driver/i2s.h" -#include -#include "HSVTable.h" - -static const char* tag = "LEDStrip"; - -LEDSTRIP::LEDSTRIP(int port, int size, int pin, LED_ORDER ledOrder, int shift, int offset) -{ - this->port = port; - this->size = size; - this->shift = shift; - this->offset = offset; - this->effSize = this->size - this->offset; - this->ledOrder = ledOrder; - - // create pixel array and buffer array - pixels = new rgbpixel_t[size]; - out_buffer_size = size * PIXEL_SIZE; - out_buffer = new uint8_t[out_buffer_size + RESET_BUFFER_SIZE]; - reset_buffer = &out_buffer[out_buffer_size + 1]; // pointer to reset buffer section - active_out_buffer = &out_buffer[0] + (offset * PIXEL_SIZE); // start of the first active - - // initialize buffer - memset(pixels, 0, this->size * sizeof(rgbpixel_t)); - memset(out_buffer, 0, out_buffer_size + RESET_BUFFER_SIZE); - - dma_frame_size = I2S_TX_DMA_BUFF_SIZE; - if((size * PIXEL_SIZE) < I2S_TX_DMA_BUFF_SIZE) { - dma_frame_size = size * PIXEL_SIZE; - } - - // Although the buffer can be smaller than total buffer size it will require more cpu interrupts - // So this provides for the entire size rounded up to the closes buffer chunk (I2S_TX_DMA_BUFF_SIZE) - int dma_buff_count = 1 + ((out_buffer_size + RESET_BUFFER_SIZE + 2) / I2S_TX_DMA_BUFF_SIZE); - - // install driver - i2s_driver_config_t i2s_config = { - .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX), - .sample_rate = SAMPLE_RATE, - .bits_per_sample = I2S_BITS_PER_SAMPLE_8BIT, - .channel_format = i2s_channel_fmt_t(I2S_CHANNEL_FMT_RIGHT_LEFT), - .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S), - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL2, // high interrupt priority, - //.intr_alloc_flags = ESP_INTR_FLAG_LOWMED, // high interrupt priority, - .dma_buf_count = dma_buff_count, // - .dma_buf_len = I2S_TX_DMA_BUFF_SIZE, - .use_apll = true - }; // possibly needed for accuracy - - //i2sEventQueue = xQueueCreate(8, sizeof(i2s_event_t)); - esp_err_t err = i2s_driver_install((i2s_port_t)port, &i2s_config, 8, &i2sEventQueue); - - if(err){ - if(err == ESP_ERR_INVALID_ARG) {ESP_LOGE(tag, "I2S driver error: Parameter error");} - else if(err == ESP_ERR_NO_MEM) {ESP_LOGE(tag, "I2S driver error: Out of Memory");} - else if(err == ESP_ERR_INVALID_STATE) {ESP_LOGE(tag, "I2S driver error: Port is in use");} - } - else{ - i2s_pin_config_t pin_config = {.bck_io_num = I2S_PIN_NO_CHANGE, - .ws_io_num = I2S_PIN_NO_CHANGE, - .data_out_num = pin, - .data_in_num = I2S_PIN_NO_CHANGE }; - - ESP_LOGV(tag, "I2S port pin configured...."); - err = i2s_set_pin((i2s_port_t)port, &pin_config); - if(err){ - if(err == ESP_ERR_INVALID_ARG) {ESP_LOGE(tag, "I2S driver error: Parameter error");} - else if(err == ESP_FAIL) {ESP_LOGE(tag, "I2S driver error: IO error");} - } - else{ - ESP_LOGV(tag, "I2S pin config success!"); - } - } - -} - - -#if(HIGH_RES_BIT_RATE == 1) -static const uint8_t bitpatterns[2] = {0b11000000, 0b11111100}; -void LEDSTRIP::updateBuff(void) { - uint8_t* buff = active_out_buffer; - for (uint16_t i = 0; i < this->effSize; i++) - { - uint8_t red = pixels[i].red >> powerDiv; - uint8_t grn = pixels[i].grn >> powerDiv; - uint8_t blu = pixels[i].blu >> powerDiv; - - *buff++ = bitpatterns[red >> 7 & 0x01]; - *buff++ = bitpatterns[red >> 6 & 0x01]; - *buff++ = bitpatterns[red >> 5 & 0x01]; - *buff++ = bitpatterns[red >> 4 & 0x01]; - *buff++ = bitpatterns[red >> 3 & 0x01]; - *buff++ = bitpatterns[red >> 2 & 0x01]; - *buff++ = bitpatterns[red >> 1 & 0x01]; - *buff++ = bitpatterns[red & 0x01]; - - *buff++ = bitpatterns[grn >> 7 & 0x01]; - *buff++ = bitpatterns[grn >> 6 & 0x01]; - *buff++ = bitpatterns[grn >> 5 & 0x01]; - *buff++ = bitpatterns[grn >> 4 & 0x01]; - *buff++ = bitpatterns[grn >> 3 & 0x01]; - *buff++ = bitpatterns[grn >> 2 & 0x01]; - *buff++ = bitpatterns[grn >> 1 & 0x01]; - *buff++ = bitpatterns[grn & 0x01]; - - *buff++ = bitpatterns[blu >> 7 & 0x01]; - *buff++ = bitpatterns[blu >> 6 & 0x01]; - *buff++ = bitpatterns[blu >> 5 & 0x01]; - *buff++ = bitpatterns[blu >> 4 & 0x01]; - *buff++ = bitpatterns[blu >> 3 & 0x01]; - *buff++ = bitpatterns[blu >> 2 & 0x01]; - *buff++ = bitpatterns[blu >> 1 & 0x01]; - *buff++ = bitpatterns[blu & 0x01]; - } - - *buff++ = 0; -} -#else -static const uint16_t bitpatterns[4] = {0x88, 0x8e, 0xe8, 0xee}; -void LEDSTRIP::updateBuff(void) -{ - uint8_t* buff = active_out_buffer; - - switch(this->ledOrder){ - case ORDER_RGB: - for (uint16_t i = 0; i < this->effSize; i++) - { - uint8_t red = pixels[i].red >> powerDiv; - uint8_t grn = pixels[i].grn >> powerDiv; - uint8_t blu = pixels[i].blu >> powerDiv; - - *buff++ = bitpatterns[red >> 6 & 0x03]; - *buff++ = bitpatterns[red >> 4 & 0x03]; - *buff++ = bitpatterns[red >> 2 & 0x03]; - *buff++ = bitpatterns[red & 0x03]; - - *buff++ = bitpatterns[grn >> 6 & 0x03]; - *buff++ = bitpatterns[grn >> 4 & 0x03]; - *buff++ = bitpatterns[grn >> 2 & 0x03]; - *buff++ = bitpatterns[grn & 0x03]; - - *buff++ = bitpatterns[blu >> 6 & 0x03]; - *buff++ = bitpatterns[blu >> 4 & 0x03]; - *buff++ = bitpatterns[blu >> 2 & 0x03]; - *buff++ = bitpatterns[blu & 0x03]; - } - break; - case ORDER_RBG: - for (uint16_t i = 0; i < this->size; i++) - { - uint8_t red = pixels[i].red >> powerDiv; - uint8_t grn = pixels[i].grn >> powerDiv; - uint8_t blu = pixels[i].blu >> powerDiv; - - *buff++ = bitpatterns[red >> 6 & 0x03]; - *buff++ = bitpatterns[red >> 4 & 0x03]; - *buff++ = bitpatterns[red >> 2 & 0x03]; - *buff++ = bitpatterns[red & 0x03]; - - *buff++ = bitpatterns[blu >> 6 & 0x03]; - *buff++ = bitpatterns[blu >> 4 & 0x03]; - *buff++ = bitpatterns[blu >> 2 & 0x03]; - *buff++ = bitpatterns[blu & 0x03]; - - *buff++ = bitpatterns[grn >> 6 & 0x03]; - *buff++ = bitpatterns[grn >> 4 & 0x03]; - *buff++ = bitpatterns[grn >> 2 & 0x03]; - *buff++ = bitpatterns[grn & 0x03]; - } - break; - case ORDER_GRB: - for (uint16_t i = 0; i < this->size; i++) - { - uint8_t red = pixels[i].red >> powerDiv; - uint8_t grn = pixels[i].grn >> powerDiv; - uint8_t blu = pixels[i].blu >> powerDiv; - - *buff++ = bitpatterns[grn >> 6 & 0x03]; - *buff++ = bitpatterns[grn >> 4 & 0x03]; - *buff++ = bitpatterns[grn >> 2 & 0x03]; - *buff++ = bitpatterns[grn & 0x03]; - - *buff++ = bitpatterns[red >> 6 & 0x03]; - *buff++ = bitpatterns[red >> 4 & 0x03]; - *buff++ = bitpatterns[red >> 2 & 0x03]; - *buff++ = bitpatterns[red & 0x03]; - - *buff++ = bitpatterns[blu >> 6 & 0x03]; - *buff++ = bitpatterns[blu >> 4 & 0x03]; - *buff++ = bitpatterns[blu >> 2 & 0x03]; - *buff++ = bitpatterns[blu & 0x03]; - } - break; - case ORDER_GBR: - for (uint16_t i = 0; i < this->size; i++) - { - uint8_t red = pixels[i].red >> powerDiv; - uint8_t grn = pixels[i].grn >> powerDiv; - uint8_t blu = pixels[i].blu >> powerDiv; - - *buff++ = bitpatterns[grn >> 6 & 0x03]; - *buff++ = bitpatterns[grn >> 4 & 0x03]; - *buff++ = bitpatterns[grn >> 2 & 0x03]; - *buff++ = bitpatterns[grn & 0x03]; - - *buff++ = bitpatterns[blu >> 6 & 0x03]; - *buff++ = bitpatterns[blu >> 4 & 0x03]; - *buff++ = bitpatterns[blu >> 2 & 0x03]; - *buff++ = bitpatterns[blu & 0x03]; - - *buff++ = bitpatterns[red >> 6 & 0x03]; - *buff++ = bitpatterns[red >> 4 & 0x03]; - *buff++ = bitpatterns[red >> 2 & 0x03]; - *buff++ = bitpatterns[red & 0x03]; - } - break; - case ORDER_BRG: - for (uint16_t i = 0; i < this->size; i++) - { - uint8_t red = pixels[i].red >> powerDiv; - uint8_t grn = pixels[i].grn >> powerDiv; - uint8_t blu = pixels[i].blu >> powerDiv; - - *buff++ = bitpatterns[blu >> 6 & 0x03]; - *buff++ = bitpatterns[blu >> 4 & 0x03]; - *buff++ = bitpatterns[blu >> 2 & 0x03]; - *buff++ = bitpatterns[blu & 0x03]; - - *buff++ = bitpatterns[red >> 6 & 0x03]; - *buff++ = bitpatterns[red >> 4 & 0x03]; - *buff++ = bitpatterns[red >> 2 & 0x03]; - *buff++ = bitpatterns[red & 0x03]; - - *buff++ = bitpatterns[grn >> 6 & 0x03]; - *buff++ = bitpatterns[grn >> 4 & 0x03]; - *buff++ = bitpatterns[grn >> 2 & 0x03]; - *buff++ = bitpatterns[grn & 0x03]; - } - break; - default: //ORDER_BGR: - for (uint16_t i = 0; i < this->size; i++) - { - uint8_t red = pixels[i].red >> powerDiv; - uint8_t grn = pixels[i].grn >> powerDiv; - uint8_t blu = pixels[i].blu >> powerDiv; - - *buff++ = bitpatterns[blu >> 6 & 0x03]; - *buff++ = bitpatterns[blu >> 4 & 0x03]; - *buff++ = bitpatterns[blu >> 2 & 0x03]; - *buff++ = bitpatterns[blu & 0x03]; - - *buff++ = bitpatterns[grn >> 6 & 0x03]; - *buff++ = bitpatterns[grn >> 4 & 0x03]; - *buff++ = bitpatterns[grn >> 2 & 0x03]; - *buff++ = bitpatterns[grn & 0x03]; - - *buff++ = bitpatterns[red >> 6 & 0x03]; - *buff++ = bitpatterns[red >> 4 & 0x03]; - *buff++ = bitpatterns[red >> 2 & 0x03]; - *buff++ = bitpatterns[red & 0x03]; - } - break; - } -} -#endif - -void LEDSTRIP::show(bool update) -{ - if(update){ updateBuff(); }; - - //i2s_stop((i2s_port_t)this->port); - i2s_start((i2s_port_t)this->port); - i2s_zero_dma_buffer((i2s_port_t)this->port); - i2s_write_data(out_buffer, out_buffer_size + RESET_BUFFER_SIZE); - - /* - i2s_event_t i2s_event; - while(1){ - if(xQueueReceive(i2sEventQueue, &i2s_event, 100)){ - if(i2s_event.type == I2S_EVENT_TX_DONE) { break;} - }else{ - break; - } - } - */ -} - -void LEDSTRIP::setPowerDiv(uint8_t div){ - if(div < 0){div = 0;} - if(div > 4){div = 4;} - powerDiv = div; -} - -// Function to write data to the I2S buffer -void LEDSTRIP::i2s_write_data(const void *data, size_t len) -{ - size_t bytesWritten = 0; - - while (bytesWritten < len) { - size_t bytesToWrite = len - bytesWritten; - - size_t written = 0; - esp_err_t err = i2s_write(I2S_NUM_0, (const char*)data + bytesWritten, bytesToWrite, &written, portMAX_DELAY); - if (err != ESP_OK) { - // Handle error - ESP_LOGE(tag, "i2s send error: %d", err); - break; - } - - bytesWritten += written; - } -} - -inline int LEDSTRIP::calcIndex(int index) -{ - //int x = (index + shift) % effSize; - //if(x < 0) { // convert nex index to positive range - // x += effSize; - //} - //return x + offset; - int x = (index + shift) % effSize; - x = (x < 0) ? (x + effSize) : x; - return (x + offset) % effSize; -} - -void LEDSTRIP::setPixel(int index, rgbpixel_t& col) -{ - pixels[calcIndex(index)] = col; -} - -void LEDSTRIP::setPixel(int index, const rgbpixel_t col) -{ - pixels[calcIndex(index)] = col; -} - -/* -void LEDSTRIP::setPixel(int index, rgbpixel_t col, uint8_t scale) -{ - uint16_t n = scale + 1; - uint8_t r = (col.red * n) >> 8; - uint8_t g = (col.grn * n) >> 8; - uint8_t b = (col.blu * n) >> 8; - pixels[calcIndex(index)] = {r, g, b}; -} -*/ - -void LEDSTRIP::setPixelRaw(int index, rgbpixel_t& col){ - pixels[index] = col; -} - -void LEDSTRIP::setPixelMirrored(int index, rgbpixel_t col) -{ - pixels[calcIndex(index)] = col; - pixels[calcIndex(-index-1)] = col; -} - -rgbpixel_t LEDSTRIP::getPixel(int index) -{ - return pixels[calcIndex(index)]; -} - -void LEDSTRIP::rotatePixels(LED_DIR dir) -{ - // store the shifted out pixels - rgbpixel_t tPix; - if(dir == DIR_FWD){ - tPix = pixels[size -1]; - for(int i=size-1; i > offset; i--){ - pixels[i] = pixels[i-1]; - } - pixels[offset] = tPix; - }else{ - tPix = pixels[offset]; - for(int i=offset; i < size-1; i++){ - pixels[i] = pixels[i+1]; - } - pixels[size-1] = tPix; - } -} - -void LEDSTRIP::shiftPixels(int numPixels, LED_DIR dir) -{ - // Calculate the shift direction and absolute shift count - int shiftDir = (dir == DIR_FWD) ? 1 : -1; - int absShiftCount = (numPixels % this->effSize) * shiftDir; - - // Shift the pixels by swapping them in place using circular buffering - for (int i = 0; i < this->effSize; i++) { - rgbpixel_t temp = pixels[i]; - int j = i; - - while (true) { - int k = j + absShiftCount; - - if (k < 0) { - k += this->effSize; - } else if (k >= this->effSize) { - k -= this->effSize; - } - - if (k == i) { - break; - } - - pixels[j] = pixels[k]; - j = k; - } - - pixels[j] = temp; - - // Check if we have completed a cycle - if (j == i + absShiftCount) { - break; - } - } -} - -void scalePixel(rgbpixel_t& pix, uint8_t _scale) -{ - uint16_t n = _scale + 1; - pix.red = (pix.red * n) >> 8; - pix.grn = (pix.grn * n) >> 8; - pix.blu = (pix.blu * n) >> 8; -} - -void linearizePixel(rgbpixel_t& pix){ - pix.red = ((int)pix.red * (int)pix.red ) >> 8; - pix.grn = ((int)pix.grn * (int)pix.grn ) >> 8; - pix.blu = ((int)pix.blu * (int)pix.blu ) >> 8; -} - - -void PixelFadeToBlack(rgbpixel_t& pix, uint8_t fadeValue) { - pix.red = (pix.red <= 8) ? 0 : pix.red - ((pix.red * fadeValue)>>8); - pix.grn = (pix.grn <= 8) ? 0 : pix.grn - ((pix.grn * fadeValue)>>8); - pix.blu = (pix.blu <= 8) ? 0 : pix.blu - ((pix.blu * fadeValue)>>8); -} - -void LEDSTRIP::zeroPixels(void) -{ - for(int i=0; i < this->size; i++){ - pixels[i] = {0,0,0}; - } -} - -void LEDSTRIP::fill(rgbpixel_t color, int startIndex, int count) -{ - int endIndex = startIndex + count; - for (int i = startIndex; i < endIndex; i++) { - pixels[calcIndex(i)] = color; - } -} - -// a factor of 0=no changer, factor=255 newCol replaces 100% -void LEDSTRIP::transitionPixel(int index, rgbpixel_t& newCol, uint8_t factor) -{ - int i = calcIndex(index); - int f = factor + 1; - pixels[i].red = (pixels[i].red * (256 - f) + newCol.red * f) >> 8; - pixels[i].grn = (pixels[i].grn * (256 - f) + newCol.grn * f) >> 8; - pixels[i].blu = (pixels[i].blu * (256 - f) + newCol.blu * f) >> 8; -} - -LED_ORDER getRGBOrder(const char* order){ - if(strcmp(order, "rgb")==0){ return ORDER_RGB; } - if(strcmp(order, "rbg")==0){ return ORDER_RBG; } - if(strcmp(order, "grb")==0){ return ORDER_GRB; } - if(strcmp(order, "gbr")==0){ return ORDER_GBR; } - if(strcmp(order, "brg")==0){ return ORDER_BRG; } - if(strcmp(order, "bgr")==0){ return ORDER_BGR; } - else{ return ORDER_GRB; } -} \ No newline at end of file diff --git a/z_old/LEDStrip.h b/z_old/LEDStrip.h deleted file mode 100644 index 6c18f0a..0000000 --- a/z_old/LEDStrip.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef LEDSTRIP_H -#define LEDSTRIP_H - -//#include -#include "LEDStrip.h" -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "esp_intr_alloc.h" - -#define HIGH_RES_BIT_RATE 0 - -#if(HIGH_RES_BIT_RATE == 1) - #define PIXEL_SIZE (8*3) - #define SAMPLE_RATE (360000) // 1.6us cycle - #define RESET_BUFFER_SIZE (100 * PIXEL_SIZE) // led latching timeout 300us mininum (50us older chips) -#else - // This can be set to 1 (normally 50) as long at the update freq isn't fast enough to interfere with the required reset length time - // This reduces memory requirements - #define RESET_PIXELS 1 - #define PIXEL_SIZE (4*3)// each colour takes 4 bytes and 3 colors per pixel - #define SAMPLE_RATE (160000) // 1.6us cycle - #define RESET_BUFFER_SIZE (RESET_PIXELS * PIXEL_SIZE) // led latching timeout 4 or more pixel lengths -#endif - -#define I2S_TX_DMA_BUFF_SIZE 128 // smaller buffer means it will start quicker - -typedef struct{ - uint8_t red; - uint8_t grn; - uint8_t blu; -} rgbpixel_t; - -enum LED_DIR{DIR_REV, DIR_FWD}; - -enum LED_ORDER{ORDER_RGB, ORDER_RBG, ORDER_GRB, ORDER_GBR, ORDER_BRG, ORDER_BGR}; - -LED_ORDER getRGBOrder(const char* order); - -void PixelFadeToBlack(rgbpixel_t& pix, uint8_t fadeValue); - -void scalePixel(rgbpixel_t& pix, uint8_t _scale); -void linearizePixel(rgbpixel_t& pix); -//rgbpixel_t scalePixel(rgbpixel_t pix, uint8_t _scale); - -//void i2sDmaInterruptHandler(void *arg); - -class LEDSTRIP { - public: - SemaphoreHandle_t i2sSemaphore; - int effSize; - int size; - int shift; - int offset; - int powerDiv = 0; - LED_ORDER ledOrder; - rgbpixel_t* pixels; - QueueHandle_t i2sEventQueue; - - LEDSTRIP(int port, int size, int pin, LED_ORDER ledOrder, int shift=0, int offset=0); - // process buffer before sending - void updateBuff(void); - // Send data to dma and I2S port - void show(bool update=true); - - void setPixel(int index, rgbpixel_t& col); - void setPixel(int index, const rgbpixel_t col); - void setPixel(int index, rgbpixel_t& col, uint8_t scale=255); - //void setPixelTrueHue(int index, int hueAngle); - //void setPixelPowerHue(int index, int hueAngle); - //void setPixelSineHue(int index, int hueAngle); - void setPixelRaw(int index, rgbpixel_t& col); - - void setPixelMirrored(int index, rgbpixel_t col); - rgbpixel_t getPixel(int index); - - //void scale(rgbpixel_t& pix, uint8_t _scale); - void fill(rgbpixel_t color, int startIndex, int count); - void fade(rgbpixel_t& col); - void zeroPixels(void); - //void setMirrored(void); - - // mirror pixels about the shift position - void rotatePixels(LED_DIR dir); - void shiftPixels(int numPixels, LED_DIR dir); - void transitionPixel(int index, rgbpixel_t& newCol, uint8_t factor); - //rgbpixel_t hueToRGB(uint8_t hue, uint8_t sat, uint8_t val); - - void setPowerDiv(uint8_t div); - - - private: - static int instanceCount; //number in class instances - - int port; - - - //intr_handle_t i2sInterruptHandle; - - int dma_frame_size; - // dma output buffer - uint8_t* out_buffer; - int out_buffer_size; - // pointer to actual active part of buffer - uint8_t* active_out_buffer; - // index position calculation - uint8_t* reset_buffer; - void i2s_write_data(const void *data, size_t size); - int calcIndex(int ind); - -}; - -//void IRAM_ATTR i2s0DmaTransmitComplete(void* arg); -//void IRAM_ATTR i2s1DmaTransmitComplete(void* arg); - -#endif diff --git a/z_old/color_tools.cpp b/z_old/color_tools.cpp deleted file mode 100644 index 3dc53d0..0000000 --- a/z_old/color_tools.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "color_tools.h" -#include - -#define MAX_HUE 360.0 - - -/************************* CLASS - HUE PALLET DISPENSER ************************/ - -HUE_PALLET_DISPENSER::HUE_PALLET_DISPENSER(void){ - Initialize(0, 360, 6); -} - -void HUE_PALLET_DISPENSER::Initialize(float hue, float range, int colSteps){ - this->range = range; - this->hueSteps = colSteps; - - this->startHue = hue - this->range / 2; - if(this->startHue < 0.0){ - this->startHue += MAX_HUE; - }else if(this->startHue > MAX_HUE){ - this->startHue -= MAX_HUE; - } - - this->hueIndex = 0; - - if(this->hueSteps <= 1){ - this->hueIncrement = 0.0; - this->currHue = hue; - }else{ - this->hueIncrement = this->range / (this->hueSteps - 1); - } -} - - -int HUE_PALLET_DISPENSER::GetNextPalletHue(void){ - if(this->hueSteps > 1){ - this->currHue = this->startHue + this->hueIndex * this->hueIncrement; - if(this->currHue < 0){ - this->currHue += MAX_HUE; - }else if(this->currHue > MAX_HUE){ - this->currHue -= MAX_HUE; - } - - // TODO Remove later - //rgbpixel_t p = HUEtoRGB(huePallet.currHue); - //Log.traceln(" index: %d, hue= %F, col: %d, %d, %d", huePallet.hueIndex, huePallet.currHue, p.red, p.grn, p.blu); - - this->hueIndex = ++this->hueIndex % this->hueSteps; - return round(this->currHue); - }else{ - return round(this->currHue); - } -} - -float HUE_PALLET_DISPENSER::PeekNextPalletHue(int hueOffset){ - float tempHue = this->startHue + (this->hueIndex + hueOffset) * this->hueIncrement; - - if(tempHue < 0){ - tempHue += MAX_HUE; - }else if(tempHue > MAX_HUE){ - tempHue -= MAX_HUE; - } - - return tempHue; -} - -void HUE_PALLET_DISPENSER::SetHueIndex(int hueIndex){ - this->currHue = hueIndex; -} diff --git a/z_old/color_tools.h b/z_old/color_tools.h deleted file mode 100644 index 176ef2c..0000000 --- a/z_old/color_tools.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef _COLOR_TOOLS_H -#define _COLOR_TOOLS_H - - -class HUE_PALLET_DISPENSER { - public: - float range = 1.0; - float hueIncrement = 1.0; - float currHue = 1.0; - int hueIndex = 0; - int hueSteps = 1; - float startHue = 0; - - //HUE_PALLET_DISPENSER(float hue1, float hue2, int colSteps); - HUE_PALLET_DISPENSER(void); - void Initialize(float hue, float range, int colSteps); - int GetNextPalletHue(void); - float PeekNextPalletHue(int offset); - void SetHueIndex(int hueIndex); - private: -}; - -enum SPEED_PROFILE {SPEED_SIMPLE, SPEED_SQUARE, SPEED_LIN_ACCEL}; - -class SPEED_DISPENSER{ - public: - - SPEED_DISPENSER(void); - - void Initialize(int min, int max, int steps, SPEED_PROFILE prof); - int GetNextSpeedInterval(void); -}; - - - - - -#endif \ No newline at end of file diff --git a/z_old/fileSystem.cpp b/z_old/fileSystem.cpp deleted file mode 100644 index d36929d..0000000 --- a/z_old/fileSystem.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "fileSystem.h" -#include -#include - -static const char* tag = "fs"; - -void Init_File_System(void) -{ - if(!LittleFS.begin()){ - ESP_LOGE(tag, "An Error occured while mounting LittleFS"); - return; - } - - // To format all space in LITTLEFS - // LITTLEFS.format() - - // Get all information of your LITTLEFS - ESP_LOGD(tag, "File system info."); - ESP_LOGD(tag, "Total: %d, Used: %d, Free:%d", LittleFS.totalBytes(), LittleFS.usedBytes(), LittleFS.totalBytes() - LittleFS.usedBytes()); - - // Open dir folder - File dir = LittleFS.open("/"); - - // Cycle all the content - printAllFiles(); -} - -void getAllDirectories(String directoryList[], int& count) -{ - File root = LittleFS.open("/"); - if (!root.isDirectory()) { return; } // Root is not a directory - - directoryList[0] = "/"; - count = 1; - - File file = root.openNextFile(); - while (file) { - if (file.isDirectory()) { - directoryList[count] = '/' + String(file.name()); - count++; - } - file = root.openNextFile(); - } - - root.close(); -} - -void printFilesInDirectories(String directoryList[], int count) -{ - for (int i = 0; i < count; i++) { - ESP_LOGD(tag, "Dir: %s", directoryList[i].c_str()); - - File dir = LittleFS.open(directoryList[i]); - File file = dir.openNextFile(); - while (file) { - if (!file.isDirectory()) { - ESP_LOGD(tag, " File: %s", file.name()); - } - file = dir.openNextFile(); - } - dir.close(); - } -} - -void printAllFiles(void) -{ - String directories[8]; - int dirCount = 0; - - getAllDirectories(directories, dirCount); - - ESP_LOGD(tag, "File System Listing:"); - printFilesInDirectories(directories, dirCount); -} \ No newline at end of file diff --git a/z_old/fileSystem.h b/z_old/fileSystem.h deleted file mode 100644 index 1dbb701..0000000 --- a/z_old/fileSystem.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _FILESYSTEM_H -#define _FILESYSTEM_H - -#define SPIFFS LITTLEFS -#include - -const int MAX_DIRECTORIES = 8; - -void Init_File_System(void); - -void readTestFile(void); - -//void printDirectory(File dir, int numTabs = 3); - -void writeFilesToSerial(void); - -void getAllDirectories(String directoryList[], int& count); - -void printFilesInDirectories(String directoryList[], int count); - -void printAllFiles(void); - -#endif \ No newline at end of file diff --git a/z_old/my_board.cpp b/z_old/my_board.cpp deleted file mode 100644 index 8eeeb64..0000000 --- a/z_old/my_board.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include "my_board.h" - -#include -#include -#include -#include "global.h" -#include "JsonConstrain.h" - -static const char* tag = "board"; -PWM_Output *pwmOut[4]; -RAMP_Output *RearLightControl; - -void Init_Board_Pins(void) -{ - pinMode(BoardLED1, OUTPUT); - pinMode(BoardLED2, OUTPUT); - - pinMode(Button1_Pin, INPUT_PULLUP); - pinMode(Button2_Pin, INPUT_PULLUP); - pinMode(Button3_Pin, INPUT_PULLUP); - - ESP_LOGV(tag, "Board pins initialized..."); -} - -void Init_PWM_Outputs(void) -{ - File file = LittleFS.open("/cfg/relays.json"); - if(!file){ - ESP_LOGE(tag, "Error opening relays.json..."); - }else{ - StaticJsonDocument<1024> doc; - DeserializationError error = deserializeJson(doc, file); - if(!error){ - file.close(); - if(error){ ESP_LOGE(tag, "relays.json deserialize error!.."); return;} - - JsonArray jsArray = doc["relays"]; - - if(jsArray.isNull() || jsArray.size() < 1 || jsArray.size() > 4 ) { return; } - - int x = 0; - for(JsonObject obj : jsArray){ - //Default config if keys are not found - if (!obj.containsKey("pin") || !obj.containsKey("freq") || !obj.containsKey("max") || !obj.containsKey("default")) { - pwmOut[x] = new PWM_Output(0, x, 12, 500, 100.0, false); - ESP_LOGD(tag, "pwmOut[%d] default config", x); - x++; - continue; - } - - int pin; - switch(x){ - case 0: - pin = jsonConstrainInt(obj, "pin", 0, 48, RELAY1_Pin); - break; - case 1: - pin = jsonConstrainInt(obj, "pin", 0, 48, RELAY2_Pin); - break; - case 2: - pin = jsonConstrainInt(obj, "pin", 0, 48, RELAY3_Pin); - break; - default: - pin = jsonConstrainInt(obj, "pin", 0, 48, RELAY4_Pin); - } - - int freq = jsonConstrainInt(obj, "freq", 100, 2000, 500); - float maxVal = jsonConstrainInt(obj, "max", 2.0, 100.0, 95); - float defaultVal = jsonConstrainInt(obj, "default", 0.0, 100.0, 40); - ESP_LOGD(tag, "pwmOut[%d]: freq:%d, max:%F, default:%F", x, freq, maxVal, defaultVal); - - pwmOut[x] = new PWM_Output(pin, x, RELAY_RES, freq, maxVal, false); - pwmOut[x]->setOutput(defaultVal); - x++; - } - }else{ - ESP_LOGE(tag, "Deserialization error on relays.json"); - } - } -} - -int linearizeLED(float inp){ - if(inp > 100.0){ inp = 100.0;}; - return (inp*inp*0.4095f); -} - -/******************* PWM_Output Definition ********************/ - -// max: 0-100% -PWM_Output::PWM_Output(uint8_t pin, uint8_t ch, int res, uint32_t freq, float maxDuty, bool visionCorrected) -{ - this->currDuty = 0; - this->ch = ch; - this->maxDuty = maxDuty; - this->visionCorrected = visionCorrected; - this->freq = freq; - this->res = res; - //this->msecRampRate = msecRampRate; - pinMode(pin, OUTPUT); - if(!ledcSetup(ch, freq, res)) { - ESP_LOGE(tag, "pwmOut-> ch:%d ledcSetup failed!", ch); - return; - } - ledcAttachPin(pin, ch); - setOutput(this->currDuty); -} - -// Range is 0 to 100% -void PWM_Output::setOutput(float duty) -{ - if(duty > maxDuty) { duty = maxDuty;} - - // calculate correct duty value - int outDutyVal; - if(this->visionCorrected){ outDutyVal = linearizeLED(duty); } - else{ outDutyVal = duty * 40.95f; } - - // FIXME pwm output ramp cause a freeze here - // Smooth Transition to final duty value - /* - if(msecRampRate){ - int d = this->currOutVal; - float dutyInc = (outDutyVal - this->currOutVal)/msecRampRate; - for(;;){ - d += dutyInc; - if(d < 0){d = 0;} - if(d > 4095){d = 4095;} - ledcWrite(this->ch, d); - if(d >= outDutyVal || d <= 0){ break; } - vTaskDelay(msecRampRate); - } - ledcWrite(this->ch, outDutyVal); - this->currOutVal = outDutyVal; - } - else{ - */ - ledcWrite(this->ch, outDutyVal); - this->currOutVal = outDutyVal; - //} - - this->currDuty = duty; -} - -void PWM_Output::setFreq(uint32_t fq) -{ - uint32_t newFreq; - - if(this->freq != fq){ - newFreq = ledcChangeFrequency(this->ch, fq, this->res); - if(newFreq){ - this->freq = fq; - } - } -} - - - -/******************* RAMP_Output Definition ********************/ - - - -void Initialize_Rear_Control(int relayIndex, int buttonIndex, int rampTime, int steps, float min, float max){ - RearLightControl = new RAMP_Output(pwmOut[relayIndex], btn[buttonIndex], rampTime, steps, min, max); -} - -RAMP_Output *RAMP_Output::instance = nullptr; // Initialize the static member variable - -void longPressStartCallback(void){ - xTimerStart(RearLightControl->timerHandle, 0); -} - -void longPressStopCallback(void){ - xTimerStop(RearLightControl->timerHandle, 0); - RAMP_Output::instance->SwitchDirection(); // Call the non-static member function using the stored instance -} - -void SingleClickCallback(void){ - RAMP_Output::instance->ClickOnOff(); -} - -void RAMP_Output::TimerCallback(TimerHandle_t xTimer) { - RearLightControl->IncrementTick(); -} - -RAMP_Output::RAMP_Output(PWM_Output *output, OneButton *button, int rampTime, int steps, float min, float max) { - this->Output = output; - this->Button = button; - this->rampTime = rampTime; - this->steps = steps; - this->min = min; - this->max = max; - this->stepSize = (max - min) / steps; - - ESP_LOGD(tag, "Rear Lights: stepSize= %.2f", stepSize); - - instance = this; // Store the instance in the static member variable - - if (this->Button) { - this->Button->attachLongPressStart(longPressStartCallback); - this->Button->attachLongPressStop(longPressStopCallback); - this->Button->attachClick(SingleClickCallback); - } else { - Serial.println("Error: Button is nullptr"); - } - - Output->visionCorrected = true; - Output->currDuty = min; - Output->setOutput(min); - - timerHandle = xTimerCreate("RampTimer", pdMS_TO_TICKS(rampTime/8), pdTRUE, this, TimerCallback); -} - -void RAMP_Output::ClickOnOff(void) { - if(IsOn){ - IsOn = false; - Output->setOutput(0); - }else{ - IsOn = true; - Output->setOutput(lastDuty); - } -} - -void RAMP_Output::IncrementTick(void) { - if (dirFwd) { - // Increment output value while ensuring it doesn't exceed max - float newValue = std::min(Output->currDuty + stepSize, max); - Output->setOutput( newValue); - lastDuty = newValue; - //ESP_LOGD(tag, "up: %.2f", newValue); - } else { - // Decrement output value while ensuring it doesn't go below min - float newValue = std::max(Output->currDuty - stepSize, min); - Output->setOutput( newValue ); - lastDuty = newValue; - //ESP_LOGD(tag, "down: %.2f", newValue); - } -} - -void RAMP_Output::SwitchDirection(void) { - dirFwd = !dirFwd; -} - -// Add destructor to clean up resources -RAMP_Output::~RAMP_Output() { - xTimerDelete(timerHandle, 0); - // Add any other necessary cleanup here -} - - - diff --git a/z_old/my_board.h b/z_old/my_board.h deleted file mode 100644 index 27a93fb..0000000 --- a/z_old/my_board.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef _MY_BOARD_H -#define _MY_BOARD_H - -#include -#include "my_buttons.h" - - -#define S3MODULEKIT 0 - -//************************* - -#define BoardLED1 17 -#define BoardLED2 18 - -#define Set_Status_LED1(x) digitalWrite(BoardLED1, x) -#define Set_Status_LED2(x) digitalWrite(BoardLED2, x) - -//************************ - -#define Button1_Pin 8 -#define Button2_Pin 19 -#define Button3_Pin 0 - -#define Button1_State digitalRead(Button1_Pin) -#define Button2_State digitalRead(Button2_Pin) -#define Button3_State digitalRead(Button3_Pin) - -//*********************** - -#define I2C_SDA1_Pin 1 -#define I2C_SCL1_Pin 2 - -#define Buzzer_Pin 37 - -#if S3MODULEKIT == 1 - #define RGBLED1_Pin 48 -#else - #define RGBLED1_Pin 3 -#endif - #define RGBLED2_Pin 46 - -#define RX433_Pin 16 -#define TX433_Pin 38 - -#define VIN_12V_Pin 20 - -#define RELAY_RES 12 -#define RELAY1_Pin 45 -#define RELAY2_Pin 48 -#define RELAY3_Pin 47 -#define RELAY4_Pin 21 -#define RELAY5_Pin 35 /* test*/ - -#define FanIndex 3 - -#define TMP102_ADDR 72 - -#define buzzerCh 4 /* 0-7chs available, 0-3 used by pwm outputs */ - -#define TOUCH1_Pin 9 -#define TOUCH2_Pin 10 -#define TOUCH3_Pin 11 -#define TOUCH4_Pin 12 -#define TOUCH5_Pin 13 -#define TOUCH_SHIELD_Pin 9 - -#define EXT1_Pin 35 -#define EXT2_Pin 36 - -#define OLED_DC 7 -#define OLED_RST 6 -#define OLED_MOSI 5 -#define OLED_SCK 4 -#define OLED_CS 15 - - -int linearizeLED(float inp); - -#define SetRelay(c,val) ledcWrite(c, val); -#define SetFrontLightCorr(val) ledcWrite(FrontConstLightCh,linearizeLED(val)) -#define SetRearLightCorr(val) ledcWrite(RearConstLightCh,linearizeLED(val)) -#define SetFrontLight(val) ledcWrite(FrontConstLightCh, val) -#define SetRearLight(val) ledcWrite(RearConstLightCh,val) - -void Init_Board_Pins(void); - -void Init_PWM_Outputs(void); - -struct _relay -{ - int freq; - bool linCorr; - int max; - int min; -}; - -struct PWMOUT{ - float max; - bool visionCorrected; - int resolution; - int frequency; -}; - -class PWM_Output { - public: - float currDuty; - bool visionCorrected; - PWM_Output(uint8_t pin, uint8_t ch, int res, uint32_t freq, float maxDuty, bool visionCorrected=false); - void setOutput(float duty); - void setFreq(uint32_t fq); - - float getMaxDuty() const { - return maxDuty; - } - void setMaxDuty(float duty) { - // add any validation or constraints here - if(duty < 0) {duty = 0.0;} - else{if(duty > 100.0) {duty = 100.0;}} - maxDuty = duty; - } - - private: - uint8_t ch; - uint32_t freq; - uint8_t res; - uint8_t currOutVal; - float maxDuty; - int msecRampRate; - -}; - -extern PWM_Output *pwmOut[4]; - - -// Push button Ramp Up/Down Logic for Lights -class RAMP_Output { - public: - TimerHandle_t timerHandle; - RAMP_Output(PWM_Output *output, OneButton *button, int rampTime, int steps, float min, float max); - ~RAMP_Output(); - void IncrementTick(void); - void SwitchDirection(void); - void ClickOnOff(void); - static void TimerCallback(TimerHandle_t xTimer); - static RAMP_Output *instance; // Static member variable to store an instance - private: - PWM_Output *Output; - OneButton *Button; - int steps; - int rampTime; - float min; - float max; - float stepSize; - bool dirFwd = true; - float lastDuty; - bool IsOn = true; - -}; - -void Initialize_Rear_Control(int relayIndex, int buttonIndex, int rampTime, int steps, float min, float max); - -#endif diff --git a/z_old/my_buttons.cpp b/z_old/my_buttons.cpp deleted file mode 100644 index d1465b3..0000000 --- a/z_old/my_buttons.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "my_buttons.h" -#include "my_board.h" -#include "global.h" -#include "led_strip.h" -#include "my_buzzer.h" - -static const char* tag = "button"; - -OneButton *btn[3]; - -void Init_ButtonEvents(void) -{ - btn[0] = new OneButton(btn1Pin, true, true); - btn[1] = new OneButton(btn2Pin, true, true); - btn[2] = new OneButton(btn3Pin, true, true); - - if(btn[0] != NULL){ - btn[0]->setDebounceTicks(DEBOUCE_TIME); // just below the update period to guarantee 1 sample delay - btn[0]->attachClick(btn1_click); - btn[0]->attachDoubleClick(btn1_doubleClick); - } - else { - ESP_LOGW(tag, "Button1 Not Initialized"); - } - - if(btn[1] != NULL){ - btn[1]->setDebounceTicks(DEBOUCE_TIME); - btn[1]->attachClick(btn2_click); - btn[1]->attachDoubleClick(btn2_doubleClick); - btn[1]->attachLongPressStart(btn2_LongPressStart); - } - else { - ESP_LOGW(tag, "Button2 Not Initialized"); - } - - if(btn[2] != NULL){ - btn[2]->setDebounceTicks(DEBOUCE_TIME); - btn[2]->attachClick(btn3_click); - btn[2]->attachDoubleClick(btn3_doubleClick); - btn[2]->attachLongPressStart(btn3_LongPressStart); - btn[2]->attachLongPressStop(btn3_LongPressStop); - } - else { - ESP_LOGW(tag, "Button3 Not Initialized"); - } - - ESP_LOGV(tag, "Initialized Buttons Events...\n"); -} - -void btn1_click() { - IncrementEventIndex(); - Pulse_LED_Status(150); - ESP_LOGD(tag, "btn1 1x"); -} - -void btn1_doubleClick() { - ESP_LOGD(tag, "btn1 2x"); -} - -void btn2_click() { - Pulse_LED_Status(150); - Buzzer_Beep(150); - // send packet - ESP_LOGD(tag, "btn2 1x"); -} - -void btn2_doubleClick() { - ESP_LOGD(tag, "btn2 2x"); -} - -void btn2_LongPressStart(){ - // scan for devices -} - -void btn3_click() { - Pulse_LED_Status(150); - ESP_LOGD(tag, "btn3 1x"); -} - -void btn3_doubleClick() { - ESP_LOGD(tag, "btn3 2x"); -} - -//bool IncFwd = true; -void btn3_LongPressStart(){ - ESP_LOGD(tag, "btn3 long press"); -} - -void btn3_LongPressStop(){ - //IncFwd = !IncFwd; // switch increment direction -} - diff --git a/z_old/my_buttons.h b/z_old/my_buttons.h deleted file mode 100644 index 467eb12..0000000 --- a/z_old/my_buttons.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _MY_BUTTONS_H -#define _MY_BUTTONS_H - -#include "OneButton.h" -#include "global.h" - -#define DEBOUCE_TIME (BUTTON_UPDATE_PERIOD-24) - -#define btn1Pin Button1_Pin -#define btn2Pin Button2_Pin -#define btn3Pin Button3_Pin - -extern OneButton *btn[3]; - - -#define Update_Buttons() btn[1]->tick(); btn[2]->tick(); btn[3]->tick(); - -void Init_ButtonEvents(void); - -void btn1_click(); -void btn1_doubleClick(); - -void btn2_click(); -void btn2_doubleClick(); -void btn2_LongPressStart(); - -void btn3_click(); -void btn3_doubleClick(); -void btn3_LongPressStart(); -void btn3_LongPressStop(); - - - -#endif \ No newline at end of file diff --git a/z_old/my_buzzer.cpp b/z_old/my_buzzer.cpp deleted file mode 100644 index 2bd8dfc..0000000 --- a/z_old/my_buzzer.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "my_buzzer.h" -#include -#include -#include -#include -#include "my_board.h" -#include "global.h" -#include "JsonConstrain.h" -#include "global.h" - -//#define buzzPin Buzzer_Pin - -static const char* tag = "buzzer"; - -MelodyPlayer* player; - -BUZZ_TUNE buzzTune[12]; -uint8_t buzzPin; - -void Init_Buzzer(uint8_t pin) -{ - File file = LittleFS.open("/cfg/buzzer.json"); - if(!file){ - file.close(); - ESP_LOGE(tag, "Error opening buzzer.json..."); - }else{ - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - if(error){ ESP_LOGE(tag, "buzzer.json deserialize error!.."); return; } - - if(jsonConstrainBool(tag, doc.as(), "en", false)){ - //player = new MelodyPlayer(buzzPin, buzzerCh, false); - int freeChannel = findUnusedLedcChannel(); - freeChannel = 1; - player = new MelodyPlayer(buzzPin, freeChannel, false); - - if(player){ - Buzzer_Load_Tunes(doc.as()); // Load Tunes - ESP_LOGD(tag, "Buzzer initialized.. using Ch:%d", freeChannel); - } - else{ - ESP_LOGE(tag, "Buzzer initialization failed.."); - } - - } - } -} - -void Buzzer_Play_Tune(TUNE_TYPE tune, bool async, bool hasPriority) -{ - static int prev_tune = -1; - static Melody melody; - - //melody = MelodyFactory.loadRtttlString( buzzTune[tune].melody.c_str() ); - //player->playAsync(melody); - - - if(!player) { - ESP_LOGV(tag, "no buzzer"); - return; - } - - //if(!player->isPlaying() || (player->isPlaying() && hasPriority)){ - // ESP_LOGD(tag, "Playing tune: %d, melody: %s", tune, buzzTune[tune].melody.c_str()); - - // if(prev_tune == tune){ - // ESP_LOGD(tag, "Same tune: %d, melody: %s", tune, buzzTune[tune].melody.c_str()); - // for(int c = 0; c < buzzTune[tune].cycles; c++){ - // ( async ) ? player->playAsync() : player->play(); - // } - // } - // else{ - melody = MelodyFactory.loadRtttlString( buzzTune[tune].melody.c_str() ); - prev_tune = tune; - ESP_LOGD(tag, "New tune: %d, melody: %s", tune, buzzTune[tune].melody.c_str()); - - for(int c = 0; c < buzzTune[tune].cycles; c++){ - ( async ) ? player->playAsync(melody) : player->play(melody); - - } - // } - //} - //else{ - // ESP_LOGD(tag, "buzzer busy"); - //} - -} - -void Buzzer_Beep(int mSecs, int freq) -{ - ledcAttachPin(buzzPin, buzzerCh); - ledcSetup(buzzerCh, 2000, 8); - ledcWrite(buzzerCh, 125); - vTaskDelay(mSecs); - ledcWrite(buzzerCh, 0); -} - -void Buzzer_Load_Tunes(const JsonObject &doc) -{ - const char* tuneName[] PROGMEM = {"boot", "error", "success", "click", "beep", - "wifi-conn", "wifi-disc", "ble-conn", "ble-disc", - "download", "waiting", "restart", "test", "ack", nullptr}; - - int listCount = 0; - while (true){ - if(tuneName[listCount] == nullptr){ break; } - listCount++; - } - - JsonObject js[listCount]; // JsonObject leaks in a loop so create separate objects - - listCount = 3; - - for(int i = 0; i < listCount; i++){ - js[i] = doc[tuneName[i]]; - buzzTune[i].cycles = jsonConstrain(tag, js[i], "cycles", 1, 100, 1); - buzzTune[i].pause = jsonConstrain(tag, js[i], "pause", 0, 100, 0); - buzzTune[i].melody = jsonConstrainString(tag, js[i], "tune", "Ack:d=16,o=5,b=112:b,b#").c_str(); - ESP_LOGD(tag, "tune %d : %s", i, buzzTune[i].melody.c_str()); - } - ESP_LOGV(tag, "loaded %d tunes", listCount); -} \ No newline at end of file diff --git a/z_old/neo_colors.h b/z_old/neo_colors.h deleted file mode 100644 index 41e4cbd..0000000 --- a/z_old/neo_colors.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef NEO_COLORS_H -#define NEO_COLORS_H - -#include "LEDStrip.h" - -/* -rgbpixel_t pallet_rainbow[1]; -rgbpixel_t pallet_white[1]; -rgbpixel_t pallet_USA[1]; -rgbpixel_t pallet_halloween[1]; -rgbpixel_t pallet_christmas[1]; -rgbpixel_t pallet_autumn[1]; -rgbpixel_t pallet_summer[1]; -rgbpixel_t pallet_neon[1]; -*/ - - - -#define USE_CORRECTED_COLORS 0 - -#define col_black color_pallet[0] -#define col_white color_pallet[1] -#define col_red color_pallet[2] -#define col_green color_pallet[3] -#define col_blue color_pallet[4] -#define col_orange color_pallet[5] -#define col_yellow color_pallet[6] -#define col_cyan color_pallet[7] -#define col_magenta color_pallet[8] -#define col_purple color_pallet[9] -#define col_pink color_pallet[10] -#define col_teal color_pallet[11] -#define col_lime color_pallet[12] -#define col_indigo color_pallet[13] -#define col_maroon color_pallet[14] -#define col_navy color_pallet[15] -#define col_olive color_pallet[16] -#define col_beige color_pallet[17] -#define col_brown color_pallet[18] -#define col_coral color_pallet[19] -#define col_gold color_pallet[20] -#define col_gray color_pallet[21] -#define col_ivory color_pallet[22] -#define col_khaki color_pallet[23] -#define col_lavender color_pallet[24] -#define col_peach color_pallet[25] -#define col_periwinkle color_pallet[26] -#define col_salmon color_pallet[27] -#define col_sienna color_pallet[28] -#define col_silver color_pallet[29] -#define col_tan color_pallet[30] -#define col_turquoise color_pallet[31] -#define col_violet color_pallet[32] - - -#if USE_CORRECTED_COLORS == 0 - -const rgbpixel_t color_pallet[] = { - {0 , 0 , 0 }, // col_black - {255, 255, 255}, // col_white - {255, 0 , 0 }, // col_red - {0 , 255, 0 }, // col_green - {0 , 0 , 255}, // col_blue - {255, 165, 0 }, // col_orange - {255, 255, 0 }, // col_yellow - {0 , 255, 255}, // col_cyan - {255, 0 , 255}, // col_magenta - {128, 0 , 128}, // col_purple - {255, 192, 203}, // col_pink - {0 , 128, 128}, // col_teal - {0 , 255, 0 }, // col_lime - {75 , 0 , 130}, // col_indigo - {128, 0 , 0 }, // col_maroon - {0 , 0 , 128}, // col_navy - {128, 128, 0 }, // col_olive - {245, 245, 220}, // col_beige - {165, 42 , 42 }, // col_brown - {255, 127, 80 }, // col_coral - {255, 215, 0 }, // col_gold - {128, 128, 128}, // col_gray - {255, 255, 240}, // col_ivory - {240, 230, 140}, // col_khaki - {230, 230, 250}, // col_lavender - {255, 218, 185}, // col_peach - {204, 204, 255}, // col_periwinkle - {250, 128, 114}, // col_salmon - {160, 82 , 45}, // col_sienna - {192, 192, 192}, // col_silver - {210, 180, 140}, // col_tan - {64 , 224, 208}, // col_turquoise - {238, 130, 238} // col_violet -}; - -#else - -const rgbpixel_t color_pallet[] = -{ - {0 , 0 , 0 }, // col_black - {255, 255, 255}, // col_white - {255, 0 , 0 }, // col_red - {0 , 255, 0 }, // col_green - {0 , 0 , 255}, // col_blue - - {255, 128, 0 }, // col_orange - {255, 255, 0 }, // col_yellow - {0 , 255, 255}, // col_cyan - {255, 0 , 255}, // col_magenta - {170, 0 , 255}, // col_purple - {255, 170, 255}, // col_pink - {0 , 128, 128}, // col_teal - {128, 255, 0 }, // col_lime - {85 , 0 , 255}, // col_indigo - {128, 0 , 0 }, // col_maroon - {0 , 0 , 128}, // col_navy - {128, 128, 0 }, // col_olive - {255, 230, 204}, // col_beige - {153, 51 , 0 }, // col_brown - {255, 102, 102}, // col_coral - {204, 153, 0 }, // col_gold - {128, 128, 128}, // col_gray - {255, 255, 204}, // col_ivory - {204, 204, 0 }, // col_khaki - {204, 153, 255}, // col_lavender - {255, 204, 153}, // col_peach - {153, 153, 255}, // col_periwinkle - {255, 153, 102}, // col_salmon - {153, 76 , 0 }, // col_sienna - {204, 204, 204}, // col_silver - {204, 153, 102}, // col_tan - {0 , 204, 204}, // col_turquoise - {204, 0 , 255} // col_violet -}; -#endif - - - - -#endif diff --git a/z_old/old/anim-list.json b/z_old/old/anim-list.json deleted file mode 100644 index fd3a27f..0000000 --- a/z_old/old/anim-list.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "whitefills":[ - { - "name":"Bottom/Up Fill", - "speed":"", - "hue-range":"", - "param1":"Time: ", - "param2":"Const Light Delay: ", - "check1":"", - "check2":"", - "check3":"", - "check4":"50% Lum" - } - ], - "animations":[ - { - "name":"Rainbow", - "speed":"Speed: ", - "hue-range":"", - "param1":"", - "param2":"", - "check1":"", - "check2":"", - "check3":"", - "check4":"50% Lum" - }, - { - "name":"Hue Spectrum", - "speed":"Speed: ", - "hue-range":"Hue Range: ", - "param1":"", - "param2":"", - "check1":"Dir Rev ", - "check2":"", - "check3":"", - "check4":"50% Lum" - }, - { - "name":"Color Pulse Cycle", - "speed":"Speed: ", - "hue-range":"Hue Range: ", - "param1":"", - "param2":"Colors: ", - "check1":"", - "check2":"", - "check3":"", - "check4":"50% Lum" - }, - { - "name":"Comets", - "speed":"Speed: ", - "hue-range":"Hue Range: ", - "param1":"Sectors: ", - "param2":"Colors: ", - "check1":"Mixed Colors ", - "check2":"Random Decay", - "check3":"Shorter Tail ", - "check4":"50% Lum" - }, - { - "name":"Dashes", - "speed":"Speed: ", - "hue-range":"Hue Range: ", - "param1":"Sectors: ", - "param2":"Colors: ", - "check1":"Mixed Colors ", - "check2":"Rotate ", - "check3":"", - "check4":"50% Lum" - }, - { - "name":"Snakes", - "speed":"Speed: ", - "hue-range":"Hue Range: ", - "param1":"Sectors: ", - "param2":"Colors: ", - "check1":"Mixed Colors ", - "check2":"Rotate ", - "check3":"", - "check4":"50% Lum" - }, - { - "name":"Sectors", - "speed":"Speed: ", - "hue-range":"Hue Range: ", - "param1":"Sectors: ", - "param2":"Colors: ", - "check1":"", - "check2":"Rotate ", - "check3":"", - "check4":"50% Lum" - }, - { - "name":"Fire", - "speed":"Speed: ", - "hue-range":"Run-time per: ", - "param1":"Cooling: ", - "param2":"Sparking: ", - "check1":"Cycle Colors ", - "check2":"", - "check3":"", - "check4":"50% Lum" - } - ] -} \ No newline at end of file diff --git a/z_old/old/anim-profile-common.json b/z_old/old/anim-profile-common.json deleted file mode 100644 index 87730d5..0000000 --- a/z_old/old/anim-profile-common.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "countdown": { - "min": 0, - "max": 98, - "hold": 1000, - "ramp": 500 - }, - "profile-index": 3 -} \ No newline at end of file diff --git a/z_old/old/anim-profile1.json b/z_old/old/anim-profile1.json deleted file mode 100644 index 96209ec..0000000 --- a/z_old/old/anim-profile1.json +++ /dev/null @@ -1,149 +0,0 @@ -{ -"name": "Basic", -"events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 1, - "hue": 40, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 2, - "hue": 80, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 150, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } -] -} \ No newline at end of file diff --git a/z_old/old/anim-profile2.json b/z_old/old/anim-profile2.json deleted file mode 100644 index 530f239..0000000 --- a/z_old/old/anim-profile2.json +++ /dev/null @@ -1,149 +0,0 @@ -{ -"name": "Rosey", -"events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } -] -} \ No newline at end of file diff --git a/z_old/old/anim-profile3.json b/z_old/old/anim-profile3.json deleted file mode 100644 index 195e8c5..0000000 --- a/z_old/old/anim-profile3.json +++ /dev/null @@ -1,149 +0,0 @@ -{ -"name": "Bluish", -"events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } -] -} \ No newline at end of file diff --git a/z_old/old/anim-profile4.json b/z_old/old/anim-profile4.json deleted file mode 100644 index 949c7ad..0000000 --- a/z_old/old/anim-profile4.json +++ /dev/null @@ -1,149 +0,0 @@ -{ -"name": "USA", -"events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } -] -} \ No newline at end of file diff --git a/z_old/old/anim-profile5.json b/z_old/old/anim-profile5.json deleted file mode 100644 index 38980f7..0000000 --- a/z_old/old/anim-profile5.json +++ /dev/null @@ -1,149 +0,0 @@ -{ -"name": "Summer", -"events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } -] -} \ No newline at end of file diff --git a/z_old/old/anim-profile6.json b/z_old/old/anim-profile6.json deleted file mode 100644 index 5fa5a46..0000000 --- a/z_old/old/anim-profile6.json +++ /dev/null @@ -1,149 +0,0 @@ -{ -"name": "Winter", -"events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } -] -} \ No newline at end of file diff --git a/z_old/old/anim-profile7.json b/z_old/old/anim-profile7.json deleted file mode 100644 index f9205df..0000000 --- a/z_old/old/anim-profile7.json +++ /dev/null @@ -1,149 +0,0 @@ -{ -"name": "Christmas", -"events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } -] -} \ No newline at end of file diff --git a/z_old/old/anim-profile8.json b/z_old/old/anim-profile8.json deleted file mode 100644 index eb06cd8..0000000 --- a/z_old/old/anim-profile8.json +++ /dev/null @@ -1,149 +0,0 @@ -{ -"name": "Halloween", -"events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } -] -} \ No newline at end of file diff --git a/z_old/old/anim-profiles copy.json b/z_old/old/anim-profiles copy.json deleted file mode 100644 index e50c0e4..0000000 --- a/z_old/old/anim-profiles copy.json +++ /dev/null @@ -1,1203 +0,0 @@ -{ - "countdown": { - "min": 0, - "max": 98, - "hold": 1000, - "ramp": 500 - }, - "profile-index": 3, - "profiles": [ - { - "name": "Profile 1", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Profile 2", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Profile 3", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Profile 4", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 75, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 1, - "hue": 0, - "hue-range": 340, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 3, - "hue": 0, - "hue-range": 340, - "speed": 75, - "param1": 30, - "param2": 60, - "check1": false, - "check2": true, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 40, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Profile 5", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Profile 5", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Wedding 7", - "events": [ - { - "anim": 0, - "hue": -1, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - }, - { - "name": "Wedding 8", - "events": [ - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 0, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - }, - { - "anim": 0, - "hue": 10, - "hue-range": 1, - "speed": 50, - "param1": 50, - "param2": 50, - "check1": false, - "check2": false, - "check3": false, - "check4": false - } - ] - } - ] -} \ No newline at end of file diff --git a/z_old/old/anim-settings.json b/z_old/old/anim-settings.json deleted file mode 100644 index 3889b0e..0000000 --- a/z_old/old/anim-settings.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "twinkle":{ - "col1": "#000000", - "col2": "#000000", - "density": 1, - "speed": 25, - "pwr": 255 - }, - "Strobe":{ - "col1": "#000000", - "col2": "#000000", - "density": 1, - "speed": 25, - "pwr": 255 - }, - "Solid":{ - "col1": "#000000", - "col2": "#000000", - "density": 1, - "pwr": 255 - }, - "Fade":{ - "col1": "#000000", - "range": 128, - "speed": 25, - "pwr": 255 - }, - "HueSwirl":{ - "col1": "#000000", - "range": 128, - "speed": 25, - "pwr": 255 - }, - "Meteors":{ - "col1": "#000000", - "col2": "#000000", - "range": 1, - "density": 1, - "speed": 25, - "pwr": 255 - }, - "Dashes":{ - "col1": "#000000", - "col2": "#000000", - "col3": "#000000", - "segments": 1, - "density": 1, - "speed": 25, - "pwr": 255 - }, - "DashesRange":{ - "col1": "#000000", - "col2": "#000000", - "range": 128, - "segments": 1, - "density": 1, - "speed": 25, - "pwr": 255 - }, - "Fire":{ - "col1": "#000000", - "cool": 25, - "spark": 25, - "speed": 25, - "pwr": 255 - }, - "Rain":{ - "col1": "#000000", - "col2": "#000000", - "range": 128, - "density": 1, - "speed": 25, - "pwr": 255 - }, - "Stacking":{ - "col1": "#000000", - "col2": "#000000", - "range": 128, - "speed": 25, - "pwr": 255 - }, - "Snake":{ - "col1": "#000000", - "col2": "#000000", - "range": 128, - "speed": 25, - "pwr": 255 - }, - "Theater":{ - "col1": "#000000", - "col2": "#000000", - "range": 128, - "speed": 25, - "step": 20, - "pwr": 255 - } -} \ No newline at end of file diff --git a/z_old/old/app-events.json b/z_old/old/app-events.json deleted file mode 100644 index fa7b393..0000000 --- a/z_old/old/app-events.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "index": 0, - "apps":[ - { - "name": "DSLR-Booth Configuration", - "events":[ - "White Fill / Countdown", - "Experience Selection", - "Select Sharing Screen", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ] - }, - { - "name": "FotoFliqs Configuration", - "events":[ - "White Fill / Countdown", - "Experience Selection", - "Preview", - "Notice!", - "Idle / Pause", - "Advertisement", - "Printing", - "Phone Input / QR Code / Apple Drop", - "", - "", - "", - "" - ] - }, - { - "name": "Touchpix Configuration", - "events":[ - "White Fill / Countdown", - "Experience Selection", - "Preview", - "Notice!", - "Idle / Pause", - "Advertisement", - "Printing", - "Phone Input / QR Code / Apple Drop", - "", - "", - "", - "" - ] - }, - { - "name": "FotoZap Configuration", - "events":[ - "White Fill / Countdown", - "Experience Selection", - "Select Sharing Screen", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ] - }, - { - "name": "Twineit Configuration", - "events":[ - "White Fill / Countdown", - "Experience Selection", - "Select Sharing Screen", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ] - } - ] -} \ No newline at end of file diff --git a/z_old/old/ble.json b/z_old/old/ble.json deleted file mode 100644 index 8cd73ca..0000000 --- a/z_old/old/ble.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "en": "true", - "core": 1, - "device-name": "ATA_COMM", - "key": "123456", - "service-uuid": "6E400001-B5A3-F393-E0A9-E50E24DCCA9E", - "char-uuid-rx": "6E400002-B5A3-F393-E0A9-E50E24DCCA9E", - "char-uuid-tx": "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" -} \ No newline at end of file diff --git a/z_old/old/board.json b/z_old/old/board.json deleted file mode 100644 index 2077f39..0000000 --- a/z_old/old/board.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "use_ver":"hwver15", - "hwver14":{ - "rgb1": 3, - "rgb2": 46, - "btn1": 8, - "btn2": 19, - "btn3": 0, - "buzzer": 37, - "touch1": 9, - "touch2": 10, - "touch3": 11, - "touch4": 12, - "touch5": 13, - "shield": 9, - "relay1": 1, - "relay2": 2, - "relay3": 3, - "relay4": 4, - "stat1": 17, - "stat2": 18, - "adc1": 20, - "oled_dc": 7, - "oled_rst": 6, - "oled_mosi": 5, - "oled_sck": 4, - "oled_cs": 15, - "ext1": 35, - "ext2": 36, - "rf433tx": 38, - "rf433rx": 16 - }, - "hwver15":{ - "rgb1": 3, - "rgb2": 9, - "btn1": 8, - "btn2": 18, - "btn3": 0, - "buzzer": 42, - "touch1": 11, - "touch2": 12, - "touch3": 13, - "touch4": 21, - "touch5": -1, - "shield": 14, - "relay1": 38, - "relay2": 48, - "relay3": 47, - "relay4": 21, - "stat1": 39, - "stat2": 37, - "adc1": 10, - "oled_dc": 7, - "oled_rst": 6, - "oled_mosi": 5, - "oled_sck": 4, - "oled_cs": 15, - "ext1": 41, - "ext2": -1, - "rf433tx": 40, - "rf433rx": 16 - } -} diff --git a/z_old/old/led-devices.json b/z_old/old/led-devices.json deleted file mode 100644 index 7f5fd74..0000000 --- a/z_old/old/led-devices.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "strip1": { - "en": true, - "size": 138, - "chip": "SK6812", - "rgb-order": "rgb", - "shift":-27, - "offset": 0, - "power-div": 0, - "pin": 3, - "i2s-ch": 0, - "core": 1 - }, - "strip2": { - "en": false, - "size": 20, - "chip": "SK6812", - "rgb-order": "grb", - "shift":0, - "offset": 0, - "power-div": 0, - "pin": 46, - "i2s-ch": 1, - "core": 0 - }, - "front-light": { - "en": true, - "relay": 0, - "core": 1, - "style": 0, - "delay": 0.75 - }, - "rear-light": { - "en": true, - "relay": 1, - "button": 2, - "min": 0.0, - "max": 100.0, - "ramp":3000, - "steps":8 - } -} \ No newline at end of file diff --git a/z_old/old/ramp-lights.json b/z_old/old/ramp-lights.json deleted file mode 100644 index 97a7052..0000000 --- a/z_old/old/ramp-lights.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "ramp-lights": - [ - { - "en": true, - "relay-index": 0, - "button-index": 0, - "min": 5.0, - "max": 100.0, - "step": 1.5, - "skip-count": 5 - }, - { - "en": true, - "relay-index": 1, - "button-index": 1, - "min": 5.0, - "max": 100.0, - "step": 1.5, - "skip-count": 5 - } - ] -} \ No newline at end of file diff --git a/z_old/old/relays.json b/z_old/old/relays.json deleted file mode 100644 index 7e11224..0000000 --- a/z_old/old/relays.json +++ /dev/null @@ -1,41 +0,0 @@ -{ -"relays": - [ - { - "en": true, - "freq": 250, - "min": 0, - "max": 100, - "default": 0, - "vision": false, - "deltarate": 0 - }, - { - "en": true, - "freq": 250, - "min": 0, - "max": 100, - "default": 0, - "vision": false, - "deltarate": 0 - }, - { - "en": true, - "freq": 250, - "min": 0, - "max": 100, - "default": 0, - "vision": true, - "deltarate": 0 - }, - { - "en": true, - "freq": 250, - "min": 0, - "max": 100, - "default": 0, - "vision": true, - "deltarate": 0 - } - ] -} \ No newline at end of file diff --git a/z_old/old/system.json b/z_old/old/system.json deleted file mode 100644 index 8cc156a..0000000 --- a/z_old/old/system.json +++ /dev/null @@ -1,146 +0,0 @@ -{ - "boardver": "board15", - "mode": 0, - "buttons": - [ - { - "en": true - }, - { - "en": true - }, - { - "en": true - } - ], -"pwmout": - [ - { - "en": true, - "freq": 250, - "min": 0, - "max": 100, - "default": 0, - "vision": false, - "deltarate": 0 - }, - { - "en": true, - "freq": 250, - "min": 0, - "max": 100, - "default": 0, - "vision": false, - "deltarate": 0 - }, - { - "en": true, - "freq": 250, - "min": 0, - "max": 100, - "default": 0, - "vision": true, - "deltarate": 0 - }, - { - "en": true, - "freq": 250, - "min": 0, - "max": 100, - "default": 0, - "vision": true, - "deltarate": 0 - } - ], - "ramp-lights": - [ - { - "en": true, - "relay-index": 0, - "button-index": 0, - "min": 5.0, - "max": 100.0, - "step": 1.5, - "skip-count": 5 - }, - { - "en": true, - "relay-index": 1, - "button-index": 1, - "min": 5.0, - "max": 100.0, - "step": 1.5, - "skip-count": 5 - } - - ], - "oled": { - "en": false, - "height": 64, - "width": 128 - }, - "t-sensor": { - "en": true, - "addr": 72, - "sp1": 85.0, - "fan-pwr1": 50.0, - "sp2": 90.0, - "fan-pwr2": 100.0, - "hyst": 1.0, - "relay": 3, - "interval": 5000 - }, - "adc": { - "ain1_factor": 1.0 - }, - "status-led":{ - "interval": 250 - }, - "strip1": { - "en": true, - "size": 138, - "chip": "SK6812", - "rgb-order": "rgb", - "shift":-27, - "offset": 0, - "power-div": 0, - "i2s-ch": 0, - "core": 1 - }, - "strip2": { - "en": true, - "size": 30, - "chip": "SK6812", - "rgb-order": "rgb", - "shift":-27, - "offset": 0, - "power-div": 0, - "i2s-ch": 0, - "core": 1 - }, - "rx433": { - "en": "true" - }, - "tx433": { - "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] - } -} diff --git a/z_old/old/touch-pins.json b/z_old/old/touch-pins.json deleted file mode 100644 index d556439..0000000 --- a/z_old/old/touch-pins.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "touchpins": - [ - { - "en": true, - "pin": 23, - "min": 100 - }, - { - "en": true, - "pin": 23, - "min": 100 - }, - { - "en": true, - "pin": 23, - "min": 100 - }, - { - "en": true, - "pin": 23, - "min": 100 - }, - { - "en": true, - "pin": 23, - "min": 100 - } - ] -} \ No newline at end of file diff --git a/z_old/wifi_temp.cpp b/z_old/wifi_temp.cpp deleted file mode 100644 index 56bcacd..0000000 --- a/z_old/wifi_temp.cpp +++ /dev/null @@ -1,1450 +0,0 @@ - -/* - wifi is started in STATION mode and tries to connected to AP saved - in the creds.json file. It will keep trying to connect forever. If - it connects then the board LEDS will toggle, the buzzer will play a tune - and the IP address will be sent to the serial port. Also the device will - be discoverable as "http://atadev.local/" - - If credentials need to be changed then double reset can be done to - trigger the AP mode and a wifi config page will be available on address - 192.168.4.1. Credentials can be entered and applied then you can reset - the device so it connects with the correct credentials. - -*/ -#include "my_wifi.h" - -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "global.h" -#include -#include "common/my_buzzer.h" -#include "my_board.h" -#include "common/led_animation.h" -#include "led_strip.h" -#include "common/fileSystem.h" -#include "JsonConstrain.h" -#include "led_strip.h" -#include "my_oled.h" -#include "BTSerial.h" -#include "esp_log.h" - -#include "firmware_html.h" - -int RebootSystem = 0; -#define WIFI_TIMEOUT_MS 10000 - -static const char* tag = "wifi"; - -bool WifiClientConnected = false; -AsyncWebServer webServer(80); -DNSServer *dnsServer; -#define DNS_PORT 53 - -#define StartDelayedRebooth RebootSystem = 1000/BUTTON_UPDATE_PERIOD; // start reboot countdown for 1sec - -String ssid; -String passPhrase; - -String AP_SSID; -String AP_Pass; -String mDnsName; -String HostName; - -IPAddress local_IP(192,168,10,1); -IPAddress gateway(192,168,10,200); -IPAddress subnet(255,255,255,0); - -// for file manager page -String filesDropdownOptions((char*)0); -String dirDropdownOptions((char*)0); -String savePath((char*)0); // needed for storing file when editing a file -String savePathInput((char*)0); -const char* http_username = "admin"; -const char* http_password = "admin"; -const char* param_delete_path = "delete-path"; -const char* param_edit_path = "edit-path"; -const char* param_dir_pad = "dir-path"; -const char* param_edit_textarea = "edit-textarea"; -const char* param_save_path = "save-path"; -String allowedExtensionsForEdit = "txt, h, htm, html, css, cpp, js, json, ini, cfg"; -//const char* jquery = "/jquery-3.6.3.min.js"; - -void Init_Wifi_Task(void) -{ - File file = LittleFS.open("/cfg/wifi.json", "r"); - if(!file){ - ESP_LOGE(tag, "Failed to open wifi.json!"); - file.close(); - return; - } - - // Parse the JSON file - StaticJsonDocument<1024> doc; - DeserializationError error = deserializeJson(doc, file); - if(!error){ - JsonObject wifiJson = doc["wifi"]; - file.close(); - mDnsName = jsonConstrainString(tag, wifiJson,"mdns-name", "atadev"); - ESP_LOGV(tag, "mDnsName: %s", mDnsName.c_str()); - - if(jsonConstrainBool(tag, wifiJson, "en", false)){ - JsonObject j = doc["cred1"]; - Wifi_Read_Credentials( j ); - xTaskCreatePinnedToCore(Wifi_Task, "Wifi_Task", 1024*10, NULL, 1, NULL, CONFIG_ARDUINO_RUNNING_CORE); - ESP_LOGV(tag, "Initialized WiFi (task created)..."); - } - - JsonObject ap = doc["ap"]; - AP_SSID = jsonConstrainString(tag, ap, "ssid", "ATA_AP"); - if(jsonConstrainBool(tag, ap, "append-id", true)){ - String macHex = String(chipInfo.macByte[1], HEX) + String(chipInfo.macByte[0], HEX); - AP_SSID += "_"; - macHex.toUpperCase(); - AP_SSID += macHex; - } - AP_Pass = jsonConstrainString(tag, ap, "pass", "12345678"); - }else{ - ESP_LOGE(tag, "Deserialization error for wifi.json"); - } -} - -void onWiFiEvent(WiFiEvent_t event) -{ - //Serial.printf("[WiFi-event] event: %d\n", event); - switch (event) { - case ARDUINO_EVENT_WIFI_READY: - //Serial.println("WiFi interface ready"); - break; - case ARDUINO_EVENT_WIFI_SCAN_DONE: - //Serial.println("Completed scan for access points"); - break; - case ARDUINO_EVENT_WIFI_STA_START: - //Serial.println("WiFi client started"); - break; - case ARDUINO_EVENT_WIFI_STA_STOP: - //Serial.println("WiFi clients stopped"); - break; - case ARDUINO_EVENT_WIFI_STA_CONNECTED: - WifiClientConnected = true; - //Serial.println("Connected to access point"); - break; - case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: - WifiClientConnected = false; - ESP_LOGV(tag,"WiFi Disconnected"); - //Buzzer_Play_Tune(TUNE_WIFI_DISCONNECTED); - break; - case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: - //Serial.println("Authentication mode of access point has changed"); - break; - case ARDUINO_EVENT_WIFI_STA_GOT_IP: - ESP_LOGV(tag,"My IP: %s", WiFi.localIP().toString()); - Wifi_Start_MDNS(); - Buzzer_Play_Tune(TUNE_WIFI_CONNECTED); - break; - case ARDUINO_EVENT_WIFI_STA_LOST_IP: - //Serial.println("Lost IP address and IP address is reset to 0"); - break; - case ARDUINO_EVENT_WPS_ER_SUCCESS: - //Serial.println("WiFi Protected Setup (WPS): succeeded in enrollee mode"); - break; - case ARDUINO_EVENT_WPS_ER_FAILED: - //Serial.println("WiFi Protected Setup (WPS): failed in enrollee mode"); - break; - case ARDUINO_EVENT_WPS_ER_TIMEOUT: - // Serial.println("WiFi Protected Setup (WPS): timeout in enrollee mode"); - break; - case ARDUINO_EVENT_WPS_ER_PIN: - //Serial.println("WiFi Protected Setup (WPS): pin code in enrollee mode"); - break; - case ARDUINO_EVENT_WIFI_AP_START: - //Serial.println("WiFi access point started"); - break; - case ARDUINO_EVENT_WIFI_AP_STOP: - //Serial.println("WiFi access point stopped"); - break; - case ARDUINO_EVENT_WIFI_AP_STACONNECTED: - //Serial.println("Client connected"); - break; - case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED: - ESP_LOGV(tag,"SoftAP Client Disconnected"); - //Buzzer_Play_Tune(TUNE_WIFI_DISCONNECTED); - break; - case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED: - ESP_LOGV(tag,"SoftAP Client Connected"); - Buzzer_Play_Tune(TUNE_WIFI_CONNECTED); - break; - case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED: - //Serial.println("Received probe request"); - break; - case ARDUINO_EVENT_WIFI_AP_GOT_IP6: - //Serial.println("AP IPv6 is preferred"); - break; - case ARDUINO_EVENT_WIFI_STA_GOT_IP6: - //Serial.println("STA IPv6 is preferred"); - break; - case ARDUINO_EVENT_ETH_GOT_IP6: - //Serial.println("Ethernet IPv6 is preferred"); - break; - case ARDUINO_EVENT_ETH_START: - //Serial.println("Ethernet started"); - break; - case ARDUINO_EVENT_ETH_STOP: - //Serial.println("Ethernet stopped"); - break; - case ARDUINO_EVENT_ETH_CONNECTED: - //Serial.println("Ethernet connected"); - break; - case ARDUINO_EVENT_ETH_DISCONNECTED: - //Serial.println("Ethernet disconnected"); - break; - case ARDUINO_EVENT_ETH_GOT_IP: - // Serial.println("Obtained IP address"); - break; - default: break; - } -} - -void Wifi_Task(void *parameters) -{ - // Extend watchdog timer - esp_task_wdt_init(2, false); - - Setup_WebServer_Handlers(&webServer); - WiFi.onEvent(onWiFiEvent); - WiFi.setHostname(mDnsName.c_str()); - WiFi.softAPConfig(local_IP, gateway, subnet); - WiFi.softAP(AP_SSID.c_str(), AP_Pass.c_str()); - Wifi_Start_MDNS(); - vTaskDelay(100); - webServer.begin(); - - // Choose WIFI Mode - if(commMode == COMM_WIFI_AP_BLE){ // AP Only - WiFi.mode(WIFI_AP); - while(1){ vTaskDelay(500 / portTICK_PERIOD_MS); } - }else{ // AP & Client (dslrbooth) - esp_wifi_set_ps(WIFI_PS_NONE); - WiFi.mode(WIFI_AP_STA); - Wifi_Client_Loop(); - } -} - -void Wifi_Client_Loop(){ - while(true){ - // Wifi status check loop - if(WiFi.status() == WL_CONNECTED){ - vTaskDelay(250); - continue; - } - - // Start WiFi Client - ESP_LOGD(tag, "Wifi trying stored creds: %s..%s",ssid.c_str(), passPhrase.c_str()); - WiFi.begin(ssid.c_str(), passPhrase.c_str()); - - //Wait until connected or timeout - ESP_LOGV(tag, "WiFi Connecting..."); - unsigned long startAttemptTime = millis(); - while(WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < WIFI_TIMEOUT_MS){ - vTaskDelay(100 / portTICK_PERIOD_MS); - } - - // Delay if wifi connection fails and continue - if(WiFi.status() != WL_CONNECTED){ - ESP_LOGW(tag, "WIFI Connection Failed!"); - for(int i = 0; i < WIFI_TIMEOUT_MS/100; i++){ - vTaskDelay(100); - } - continue; - } - } -} - -void Wifi_Start_MDNS(void) -{ - ESP_LOGV(tag, "Initializing MDNS: %s", mDnsName.c_str()); - if (!MDNS.begin(mDnsName.c_str())) { - ESP_LOGE(tag, "Error setting up MDNS responder!"); - }else{ - ESP_LOGV(tag, "You can access device via http://%s.local", mDnsName); - } -} - -void Wifi_Read_Credentials(const JsonObject &credJson){ - if(credJson.isNull()){ // set generic defaults on error - ESP_LOGE(tag, "Failed to find wifi key"); - - ssid = "Generic"; - passPhrase = "password"; - //strncpy(ssid, "Generic", sizeof(ssid)-1); - //strncpy(passPhrase, "password", sizeof(passPhrase)-1); - return; - } - else{ - // TODO Restore String - ssid = jsonConstrainString(tag, credJson, "ssid", "default"); - passPhrase = jsonConstrainString(tag, credJson, "pass", "password"); - //strncpy(ssid, jsonConstrainString(tag, credJson, "ssid", "default").c_str(), sizeof(ssid)-1); - //strncpy(passPhrase, jsonConstrainString(tag, credJson, "pass", "password").c_str(), sizeof(passPhrase)-1); - } -} - -void Wifi_Save_Credentials(String newSSID, String newPass) -{ - // Open the credentials file writing - File credsFile = LittleFS.open("/cfg/wifi.json", "r+"); - if(!credsFile){ - ESP_LOGE(tag, "Failed to open wifi.json\n"); - return; - } - - // Parse the JSON file - JsonDocument doc; - DeserializationError error = deserializeJson(doc, credsFile); - if(!error){ - JsonObject cred1Json = doc.createNestedObject("cred1"); - - if(cred1Json){ - cred1Json["ssid"] = newSSID; - cred1Json["pass"] = newPass; - - // Clear file contents before saving the modified JSON - credsFile.seek(0); - - int written = serializeJson(doc, credsFile); // save to file - ESP_LOGD(tag, "Credentials saved... ssid: %s, pass: %s, size written: %d", newSSID, newPass, written); - } - credsFile.close(); - }else{ - ESP_LOGE(tag, "Deserialization error for wifi.json"); - } -} - -void Setup_WebServer_Handlers(AsyncWebServer* serv) -{ - serv->on("/dslrbooth", HTTP_GET, handleGET_DSLRBooth); - - serv->on("/", HTTP_GET, [](AsyncWebServerRequest *request){ - if(WiFi.getMode() == WIFI_AP && !WifiClientConnected){ - request->redirect("/wifi"); - }else{ - request->redirect("/home"); - } - }); - serv->on("/home", HTTP_GET, [](AsyncWebServerRequest *request){ - sendHtmlFile("/www/home.html", request, HomeHtmlProcessor); - }); - serv->on("/lights", HTTP_GET, [](AsyncWebServerRequest *request){ - sendHtmlFile("/www/lights.html", request, htmlProcessor); - }); - serv->on("/setup", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - sendHtmlFile("/www/setup.html", request, htmlProcessor); - }); - serv->on("/wifi", HTTP_GET, [](AsyncWebServerRequest *request){ - if(WiFi.getMode() == WIFI_MODE_APSTA){ - // TODO Disable navigation bar - } - sendHtmlFile("/www/wifi.html", request, htmlProcessor); - }); - serv->on("/files", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - sendHtmlFile("/www/files.html", request, htmlProcessor); - }); - serv->on("/upload", HTTP_POST, [](AsyncWebServerRequest *request) { request->send(200); }, handlePOST_Upload); - - serv->on("/download", HTTP_GET, [](AsyncWebServerRequest *request){ - if (request->hasParam("file")) { - String filename = request->getParam("file")->value(); - if (LittleFS.exists(filename)) { - fs::File file = LittleFS.open(filename, "r"); - if (file) { - request->send(LittleFS, filename, "application/octet-stream"); - file.close(); - return; - } - } - } - request->send(404, "text/plain", "File not found!"); - }); - serv->on("/delete", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - - String filename = request->getParam(param_delete_path)->value(); - if(filename !="choose"){ - LittleFS.remove(filename.c_str()); - ESP_LOGD(tag, "Deleted file: %s", filename.c_str()); - } - - request->redirect("/files"); - }); - serv->on("/edit", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - - String fileName = request->getParam(param_edit_path)->value(); - if(fileName =="new"){ - savePath = "/new.txt"; - } - else{ - savePath = fileName; - } - - ESP_LOGD(tag, "Edit file: %s", savePath.c_str()); - sendHtmlFile("/www/edit.html", request, htmlProcessor); - }); - serv->on("/save", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)){ - return request->requestAuthentication(); - } - String inputMessage((char*)0); - if (request->hasParam(param_edit_textarea)) { - inputMessage = request->getParam(param_edit_textarea)->value(); - } - if (request->hasParam(param_save_path)) { - savePath = request->getParam(param_save_path)->value(); - } - writeFile(LittleFS, savePath.c_str(), inputMessage.c_str()); - - request->redirect("/files"); - }); - serv->on("/update", HTTP_POST, handlePOST_Update, updateCallback); - - // Request Data - serv->on("/get", HTTP_GET, handleGET_Get); - // Post Data - serv->on("/post", HTTP_POST, handlePOST_Post, postFileUpload, postBody); - - serv->on("/generate_204", HTTP_GET, [](AsyncWebServerRequest *request){ - ESP_LOGD(tag, "/generate_204 ... redirect to /wifi"); - request->redirect("/wifi"); - }); - - serv->on("/hotspot-detect.html", HTTP_GET, [](AsyncWebServerRequest *request){ - ESP_LOGD(tag, "/hotspot-detect.html ... redirect to /wifi"); - request->redirect("/wifi"); - }); - - serv->on("/msftconnecttest.txt", HTTP_GET, [](AsyncWebServerRequest *request){ - ESP_LOGD(tag, "/msftconnecttest.txt ... redirect to /wifi"); - request->redirect("/wifi"); - }); - - serv->on("/reg-stick", HTTP_POST, handlePOST_RegStick); - - serv->on("/firmware", HTTP_GET, [](AsyncWebServerRequest *request){ - request->send_P(200, "text/html", firmware_html_page); - }); - - serv->onNotFound([](AsyncWebServerRequest *request){ - if(WiFi.getMode() == WIFI_MODE_APSTA){ - ESP_LOGD(tag, "OnNotFound Redirect to /wifi"); - request->redirect("/wifi"); - }else if(WiFi.getMode() == WIFI_MODE_AP){ - ESP_LOGD(tag, "OnNotFound Redirect to /home"); - request->redirect("/home"); - }else{ - request->send(404); - } - }); - - serv->on("/*", HTTP_GET, handleGET_SendFile); // send any file - -} - -void handlePOST_RegStick(AsyncWebServerRequest *request){ - -} - -bool getpostSuccess = false; -// -void handleGET_Get(AsyncWebServerRequest *request){ - if(request->hasParam("type", false, false)) { - const char* dataType = request->getParam("type", false, false)->value().c_str(); - - if(!strcmp(dataType, "app-events")){ // send json file - request->send(LittleFS, "/cfg/app-events.json", "application/json"); - return; - } - - if(!strcmp(dataType, "anim-profiles")){ // send json file - request->send(LittleFS, "/cfg/anim-profiles.json", "application/json"); - return; - } - - if(!strcmp(dataType, "anim-list")){ - request->send(LittleFS, "/cfg/anim-list.json", "application/json"); - return; - } - - if(!strcmp(dataType, "sys-summary")){ - JsonDocument doc; - CreateSysSummmaryPacket(doc); - String summary; - serializeJson(doc, summary); - request->send(200, "application/json", summary); - return; - } - - if(!strcmp(dataType, "wifi")){ - JsonDocument jsdoc; - jsdoc["ssid"] = ssid; - //jsdoc["pass"] = (int)strlen(passPhrase); - jsdoc["pass"] = passPhrase; - - String jsStr; - serializeJson(jsdoc, jsStr); - - request->send(200, "application/json", jsStr); - return; - } - } - - request->send(400, "text/plain", "Failed"); -} - -void CreateSysSummmaryPacket(JsonDocument &doc){ - JsonObject booth = doc.createNestedObject("booth"); - booth["mode"] = ""; - booth["app"] = sysProps.appName; - booth["strip1"] = (strip1) ? true : false, - booth["strip2"] = (strip2) ? true : false, - booth["front-light"] = true; - booth["rear-light"] = false; - booth["oled"] = (oled) ? true : false; - - //ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getHeapSize()-ESP.getFreeHeap()); - - JsonObject Temperature = doc.createNestedObject("temperature"); - Temperature["temp"] = sysProps.t_sensor.temperature; - Temperature["sp1"] = sysProps.t_sensor.Setpoint1; - doc["system"]["firm-ver"] = FIRMWARE_VER; - - JsonObject chip = doc.createNestedObject("chip"); - chip["flash-size"] = ""; - chip["flash-free"] = ""; - chip["ram-size"] = ESP.getHeapSize(); - chip["ram-free"] = ESP.getFreeHeap(); - - - - // Get the Wi-Fi RSSI - wifi_ap_record_t wifi_ap_info; - esp_err_t rssi_result = esp_wifi_sta_get_ap_info(&wifi_ap_info); - int rssi = 0; int wifi_ch = 0; - String encryp = ""; - if (rssi_result == ESP_OK) { - rssi = wifi_ap_info.rssi; - wifi_ch = wifi_ap_info.primary; - - wifi_auth_mode_t auth_mode = wifi_ap_info.authmode; - switch (auth_mode) { - case WIFI_AUTH_OPEN: - encryp = "Open"; - break; - case WIFI_AUTH_WEP: - encryp = "WEP"; - break; - case WIFI_AUTH_WPA_PSK: - encryp = "WPA_PSK"; - break; - case WIFI_AUTH_WPA2_PSK: - encryp = "WPA2_PSK"; - break; - case WIFI_AUTH_WPA_WPA2_PSK: - encryp = "WPA_WPA2_PSK"; - break; - case WIFI_AUTH_WPA2_ENTERPRISE: - encryp = "WPA2_ENT"; - break; - default: - encryp = "UNKNOWN"; - break; - } - } - - JsonObject wifi = doc.createNestedObject("wifi"); - wifi["client-ip"] = "XXX.XXX.XXX.XXX"; - wifi["mac-addr"] = chipInfo.macStr; - wifi["ch"] = wifi_ch; - wifi["rssi"] = rssi; - wifi["encryp"] = encryp; - - JsonObject ble = doc.createNestedObject("ble"); - ble["en"] = (sysProps.appIndex == DSLRBOOTH_INDEX)? false : true; - ble["clients"] = (BTDeviceConnected)? 1 : 0; - ble["ssid"] = BLEDeviceName; - -} - -void handlePOST_Post(AsyncWebServerRequest *request){ - ESP_LOGD(tag, "posts request.."); - if(!getpostSuccess) { request->send(400, "text/plain", "Error"); } - - request->send(200, "text/plain", "Ok"); -} - -void postFileUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) { - getpostSuccess = false; - Serial.println("post file"); -} - - -// POST Requests -int packets, postTotal; -char postType[24]; -char *postData; -void postBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){ - if (!index){ - packets = 0; - int sectors = (total + 1023 + 64) / 1024; - postData = new char[1024 * sectors]; - } - - // Accumulate Data Chunks - memcpy(postData + index, data, len); - packets++; - - if((index + len) >= total){ - ESP_LOGD(tag, "index: %d, len: %d, total: %d", index, len, total); - ESP_LOGD(tag, "packets: %d", packets); - getpostSuccess = false; - - // Check if the request contains the necessary parameters - if (request->hasParam("type", false, false)) { - const char* dataType = request->getParam("type", false, false)->value().c_str(); - ESP_LOGD(tag, "data type: %s", dataType); - - if(!strcmp(dataType, "anim-profile-common") || !strcmp(dataType, "set-countdown")){ - JsonDocument profJson(1 * 1024); - DeserializationError error = deserializeJson(profJson, postData, total); - - if(!error){ - animProps.profileIndex = profJson["profile-index"].as(); - - JsonObject countdownJson = profJson["countdown"]; - animProps.frontLight.minDuty = countdownJson["min"].as(); - animProps.frontLight.maxDuty = countdownJson["max"].as(); - animProps.frontLight.holdTime = countdownJson["hold"].as(); - animProps.frontLight.rampTime = countdownJson["ramp"].as(); - - int indexChanged = animProps.profileIndex - countdownJson["profile-index"].as(); - animProps.profileIndex = countdownJson["profile-index"].as(); - if(indexChanged){ - load_animation_profileByIndex(animProps.profileIndex); - } - - // Save to disk/flash - if(dataType[0] == 'a'){ - if(updateJsonDocument(profJson, "/cfg/anim-profile-common.json")){ - Buzzer_Beep(150, 3000); - } - } - else{ - ESP_LOGD(tag, "Post:set-countdown, index: %d, min: %.1f, max: %.1f, hold: %d, ramp: %d", animProps.profileIndex, animProps.frontLight.minDuty, animProps.frontLight.maxDuty, animProps.frontLight.holdTime, animProps.frontLight.rampTime); - Buzzer_Beep(150, 3000); - } - }else{ - ESP_LOGE(tag, "Deserialization error for wifi.json"); - } - - getpostSuccess = true; - //goto done; - } - else if(!strncmp(dataType, "anim-profile", 12)){ - if (strlen(dataType) > 12) { - int profile_index = (dataType[12] - '0' - 1) % 8; // extract index, assuming dataType has enough characters - //DynamicJsonDocument profJson(4 * 1024); - JsonDocument profJson; - DeserializationError error = deserializeJson(profJson, postData, total); - - if(!error){ - JsonArray eventsArray = profJson["events"]; - for(int i = 0; i < eventsArray.size(); i++ ){ - animProps.event[i].selfIndex = i; - animProps.event[i].animIndex = eventsArray[i]["anim"].as(); - animProps.event[i].hue = eventsArray[i]["hue"].as(); - animProps.event[i].hueRange = eventsArray[i]["hue-range"].as(); - animProps.event[i].speed = eventsArray[i]["speed"].as(); - animProps.event[i].param1 = eventsArray[i]["param1"].as(); - animProps.event[i].param2 = eventsArray[i]["param2"].as(); - animProps.event[i].check1 = eventsArray[i]["check1"].as(); - animProps.event[i].check2 = eventsArray[i]["check2"].as(); - animProps.event[i].check3 = eventsArray[i]["check3"].as(); - animProps.event[i].check4 = eventsArray[i]["check4"].as(); - animProps.event[i].countDown = 0; - } - - ESP_LOGD(tag, "Extracted/Updated active profile to animProps."); - - // Save to disk/flash - String filePath = "/cfg/anim-profile" + String(profile_index + 1) + ".json"; - if(updateJsonDocument(profJson, filePath.c_str())){ - Buzzer_Beep(150, 3000); - } - - }else{ - ESP_LOGE(tag, "Deserialization error for wifi.json"); - } - - getpostSuccess = true; - } - } - else if(!strcmp(dataType, "play-anim")){ - JsonDocument animData; - DeserializationError error = deserializeJson(animData, postData, total); - if(!error){ - ANIMATION_EVENT testEvent; - testEvent.selfIndex = animData["index"].as(); - testEvent.animIndex = animData["anim"].as(); - testEvent.hue = animData["hue"].as(); - testEvent.hueRange = animData["hue-range"].as(); - testEvent.speed = animData["speed"].as(); - testEvent.param1 = animData["param1"].as(); - testEvent.param2 = animData["param2"].as(); - testEvent.check1 = animData["check1"].as(); - testEvent.check2 = animData["check2"].as(); - testEvent.check3 = animData["check3"].as(); - testEvent.check4 = animData["check4"].as(); - - if(testEvent.selfIndex != 0){ - testEvent.selfIndex = 1; - } - ESP_LOGI(tag, "Post:play-anim, index: %d, anim: %d, hue: %d, rng: %d, speed: %d, par1: %d, par2: %d, chk1: %d, chk2: %d, chk3: %d, chk4: %d", testEvent.selfIndex, testEvent.animIndex, testEvent.hue, testEvent.hueRange, testEvent.speed, testEvent.param1, testEvent.param2, testEvent.check1, testEvent.check2, testEvent.check3, testEvent.check4); - testEvent.countDown = 0; // set to zero so param1 determines countdown time - testEvent.type = EV_TEST; - PostNewEvent(testEvent); // eventIndex always = 1 - Buzzer_Beep(150, 3000); - }else{ - ESP_LOGE(tag, "Deserialization error for play-anim"); - } - - getpostSuccess = true; - } - else if(!strcmp(dataType, "wifi")){ - JsonDocument wifiCreds; - DeserializationError error = deserializeJson(wifiCreds, postData, total); - if(!error){ - //read credentials - //const char* new_ssid = wifiCreds["ssid"]; - //const char* new_pass = wifiCreds["pass"]; - - String new_ssid = wifiCreds["ssid"]; - String new_pass = wifiCreds["pass"]; - ESP_LOGV(tag, "SSID: %s PASS: %s", new_ssid, new_pass); - // Save Credentials if different - //if(strcmp(new_ssid, ssid)!=0 || strcmp(new_pass, passPhrase)!=0){ - if(new_ssid != ssid || new_pass != passPhrase) - Wifi_Save_Credentials(new_ssid, new_pass); - StartDelayedRebooth; - } - }else{ - ESP_LOGE(tag, "Deserialization error for wifi"); - } - - getpostSuccess = true; - } - else if(!strcmp(dataType, "set-pixel")){ - JsonDocument js; - DeserializationError error = deserializeJson(js, postData, total); - if(!error){ - ANIMATION_EVENT testEvent; - testEvent.selfIndex = 1; - testEvent.animIndex = 81; - testEvent.hue = js["hue"].as(); - testEvent.param1 = js["index"].as(); - testEvent.type = EV_TEST; - PostNewEvent(testEvent); // eventIndex always = 1 - ESP_LOGD(tag, "Post: set-pixel, hue: %d, pixel: %d", testEvent.hue, testEvent.param1); - Buzzer_Beep(150, 3000); - }else{ - ESP_LOGE(tag, "Deserialization error for set-pixel"); - } - - Buzzer_Beep(50, 3000); - getpostSuccess = true; - } - else if(!strcmp(dataType, "clear-strip")){ - ANIMATION_EVENT testEvent; - testEvent.selfIndex = 1; - testEvent.animIndex = 80; - ESP_LOGD(tag, "Post: clear-strip"); - testEvent.type = EV_TEST; - PostNewEvent(testEvent); // eventIndex always = 1 - - getpostSuccess = true; - Buzzer_Beep(50, 3000); - } - else if(!strcmp(dataType, "setup-save")){ - JsonDocument js; - DeserializationError error = deserializeJson(js, postData, total); - if(!error){ - // If app index is different open app-events.json and update - if(sysProps.appIndex != js["appindex"].as()){ - File file = LittleFS.open("/cfg/app-events.json", "r+"); - if(!file){ - ESP_LOGE(tag, "Failed to open app-events.json"); - file.close(); - return; - } - - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - - if(!error){ - // Update index value - doc["index"] = js["appindex"].as(); - ESP_LOGD(tag, "New App Index = %d", doc["index"].as()); - - if(updateJsonDocument(doc, "/cfg/app-events.json")){ - Buzzer_Beep(150, 3000); - } - }else{ - ESP_LOGE(tag, "Deserialization error for app-events.json"); - } - } - }else{ - ESP_LOGE(tag, "Deserialization error for seteup-save"); - } - - // if any of the values are diiferent then open led-devices.json and update - //if app index is different open app-events.json and update - bool editJson = false; - //if(js["en1"].as() != strip1->size) { editJson = true; } - if(js["count1"].as() != strip1->size) { editJson = true; } - else if(js["shift1"].as() != strip1->shift) { editJson = true; } - else if(js["offset1"].as() != strip1->offset) { editJson = true; } - else if(js["rgb1"].as() != strip1->ledOrder) { editJson = true; } - else if(js["power1"].as() != strip1->powerDiv) { editJson = true; } - - if(editJson){ - File file = LittleFS.open("/cfg/led-devices.json", "r+"); - if(!file){ - ESP_LOGE(tag, "Failed to open led-devices.json"); - file.close(); - return; - } - - JsonDocument doc; - DeserializationError error = deserializeJson(doc, file); - file.close(); - - if(!error){ - JsonObject jsStrip1 = doc.createNestedObject("strip1"); // nested so it doesn't create a copy - - jsStrip1["en"] = true; - jsStrip1["size"] = js["count1"].as(); - jsStrip1["shift"] = js["shift1"].as(); - jsStrip1["offset"] = js["offset1"].as(); - jsStrip1["power-div"] = js["power1"].as(); - jsStrip1["rgb-order"] = js["rgb1"]; - - // Save Json File - if(updateJsonDocument(doc, "/cfg/led-devices.json")){ - Buzzer_Beep(150, 3000); - } - }else{ - ESP_LOGE(tag, "Deserialization error for led-devices.json"); - } - } - - ESP_LOGD(tag, "Post: setup-save"); - getpostSuccess = true; - Buzzer_Beep(150, 3000); - } - else if(!strcmp(dataType, "restart")){ - StartDelayedRebooth; - - ESP_LOGD(tag, "Post: restart"); - getpostSuccess = true; - Buzzer_Beep(150, 3000); - } - } - - // Delete the allocated buffer (owned by the request->_tempObject) - delete[] postData; - } -} - -bool isInternetConnected() -{ - if (WiFi.status() == WL_CONNECTED) { // check if WiFi is connected - WiFiClient client; - const int httpPort = 80; - if (client.connect("www.google.com", httpPort)) { // try to connect to Google - client.stop(); - return true; // Internet access available - } - } - return false; // Internet access not available -} - -void handlePOST_Upload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) -{ - if (!index && request->hasParam("dir-path", true, false)) { - AsyncWebParameter* p = request->getParam("dir-path",true, false); - String path = p->value() + "/" + filename; - ESP_LOGD(tag, "upload path: %s", path.c_str()); - - request->_tempFile= LittleFS.open(path, "w"); - //fs::File file = LittleFS.open(path, "w"); - if (!request->_tempFile) { - ESP_LOGE(tag, "Failed to create file!"); - return; - } - }else{ - ESP_LOGE(tag, "dir-path Param not found.."); - } - - if(len && request->_tempFile){ - request->_tempFile.write(data, len); - } - - if(final){ - request->_tempFile.close(); - request->redirect("/files"); - ESP_LOGD(tag, "UploadEnd: %s, %u B", filename.c_str(), index+len); - } -} - -void handleGET_DSLRBooth(AsyncWebServerRequest *request) -{ - static int lastCountdown = 1000; - request->send(200, "text/plain"); // send this right away to avoid comm delays - - if(request->args() >= 1){ - int x = 0; - const char* event_type = request->arg( x ).c_str(); - - if(strcmp("countdown", event_type) == 0){ - int p = request->arg(1).toInt(); - if(p > 0 && p <= 100){ - animStatus.countStatus = p; - } - - // in case "coundown_start" was missed - if(animStatus.EventsIndex != ANIM_WHITEFILL_INDEX){ - animProps.event[0].countDown = lastCountdown; - animProps.event[0].type = EV_NORMAL; - PostNewEvent(animProps.event[0]); - } - } - else if(strcmp("countdown_start", event_type) == 0){ // index=0 - int count = request->arg(1).toInt(); // retrieve countdown value - //Log.traceln(" countdown = %d", count); - if(count < 1){count = 1;} - count *= 1000; - lastCountdown = count - 500; - animProps.event[0].countDown = lastCountdown; - animProps.event[0].type = EV_NORMAL; - PostNewEvent(animProps.event[0]); - } - else if(strcmp("sharing_screen", event_type) == 0){ - animProps.event[2].type = EV_NORMAL; - PostNewEvent(animProps.event[2]); - } - else if(strcmp("session_end", event_type) == 0){ //index=1 - animProps.event[1].type = EV_NORMAL; - PostNewEvent(animProps.event[1]); - } - else{ - // else if(strcmp_P("session_start", event_type) == 0){ - // TODO determine if ramp down is active depending on session type - - /* - const char* param1 = request->arg(1).c_str(); - if(strcmp("PrintOnly", param1)){ - animStatus.Animation = ANIM_START_PRINTONLY; - xTaskNotifyGive( Strip1_Task_Handle ); - //Serial.println("ses_print..\n\r"); - }else if(strcmp("PrintAndGIF", param1)){ - animStatus.Animation = ANIM_START_PRINTGIF; - xTaskNotifyGive( Strip1_Task_Handle ); - //Serial.println("ses_prnt_gif..\n\r"); - }else if(strcmp("OnlyGIF", param1)){ - animStatus.Animation = ANIM_START_GIFONLY; - xTaskNotifyGive( Strip1_Task_Handle ); - //Serial.println("ses_gif..\n\r"); - }else if(strcmp("Boomerang", param1)){ - animStatus.Animation = ANIM_START_BOOM; - xTaskNotifyGive( Strip1_Task_Handle ); - //Serial.println("ses_boom..\n\r"); - }else if(strcmp("Video", param1)){ - animStatus.Animation = ANIM_START_VIDEO; - xTaskNotifyGive( Strip1_Task_Handle ); - //Serial.println("ses_vid..\n\r"); - } - */ - } - } -} - -bool isFirmware = true; -bool updateSuccessful = false; -void handlePOST_Update(AsyncWebServerRequest *request) -{ - bool hasError = Update.hasError(); - String responseContent = hasError ? "failed" : "success"; - String responseType = hasError ? "text/plain" : "text/html"; - int responseCode = hasError ? 500 : 200; - - AsyncWebServerResponse *response = request->beginResponse(responseCode, responseType, responseContent); - response->addHeader("status", responseContent); - request->send(response); -} - -// handlePOST_Update Callback function to install the firmware or file system bin files -void updateCallback(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) -{ - // Do Once Code - if (!index) { - size_t fileSize = UPDATE_SIZE_UNKNOWN; - // Retrieve file-size parameter - if(request->hasParam("file-size", true, false)) { // make sure param is from POST request or it will not find it - fileSize = request->getParam("file-size", true, false)->value().toInt(); - } - - // register progress callback function - Update.onProgress(updateFirmwareProgress); - updateSuccessful = false; - - //file name checks - if (filename.startsWith("ata_fw")) { - isFirmware = true; - if (!Update.begin(fileSize, U_FLASH, BoardLED2)) { - ESP_LOGD(tag, "Firmware update failed to start"); - return; - } - ESP_LOGD(tag, "Updating Firmware with: %s Size:%d ", filename.c_str(), fileSize); - } - else if (filename.startsWith("ata_fs")) { - isFirmware = false; - if (!Update.begin(fileSize, U_SPIFFS, BoardLED2)) { - ESP_LOGD(tag, "LittleFS update failed to start"); - return; - } - ESP_LOGD(tag, "Updating File System with: %s Size:%d ", filename.c_str(), fileSize); - } - else { - ESP_LOGD(tag, "Unsupported file type"); - return; - } - } - - // Writing... - if (!Update.hasError()) { - if (Update.write(data, len) != len) { - Update.printError(Serial); - } - } - - // All Done... - if (final) { - vTaskDelay(100); - if(isFirmware) { // firmware update - if (Update.end(true)) { - RebootSystem = true; - updateSuccessful = true; - ESP_LOGD(tag, "firmware update successful: %d", index + len); - } - else { - Update.printError(Serial); - } - } - else{ // file system update - if(Update.end(true)) { - updateSuccessful = true; - ESP_LOGD(tag, "file system update successful!"); - } - else { - Update.printError(Serial); - } - } - } -} - -// Server requested files that aren't template processed -void handleGET_SendFile(AsyncWebServerRequest *request)// try this later "^/(img|favicon).*" -{ - String filePath = request->url(); - const char* ext = getFileExtension(filePath.c_str()); - const char* contentType = getFileType(ext); - - if( contentType == NULL ){ - request->send(404); - return; - } - - if(filePath.c_str()[0] != '/'){ - filePath = '/' + filePath; - } - - if (!strcmp(ext,"html") || !strcmp(ext, "htm") || !strcmp(ext, "css") || !strcmp(ext, "js")) { - if(!filePath.startsWith("/www/")){ - filePath = "/www" + filePath; - } - } - - ESP_LOGD(tag, "Sent: %s", filePath.c_str()); - request->send(LittleFS, filePath, contentType); -} - -String listDir(String directoryList[], int count) -{ - String listedFiles; - - for (int i = 0; i < count; i++) { - // directory html - listedFiles += "Dir: "; - listedFiles += directoryList[i]; - listedFiles += "/-\n"; - - filesDropdownOptions += "\n"; - - dirDropdownOptions += "\n"; - - File dir = LittleFS.open(directoryList[i]); - File file = dir.openNextFile(); - while (file) { - String fileName = file.name(); - if (!file.isDirectory()) { - //Serial.println(" File: " + String(file.name())); - listedFiles += "  "; - listedFiles += fileName; - listedFiles += ""; - listedFiles += convertFileSize(file.size()); - listedFiles += "\n"; - - filesDropdownOptions += "\n"; - } - file = dir.openNextFile(); - } - dir.close(); - } - - return listedFiles; -} - -char* readFile(fs::FS &fs, const char* path) { - File file = fs.open(path, "r"); - if (!file || file.isDirectory()) { - return nullptr; - } - - size_t fileSize = file.size(); - char* fileContent = new char[fileSize + 1]; // +1 for null-terminator - - size_t bytesRead = file.readBytes(fileContent, fileSize); - file.close(); - - fileContent[bytesRead] = '\0'; // Set null-terminating character - - if (bytesRead != fileSize) { - delete[] fileContent; - return nullptr; - } - - return fileContent; -} - -void writeFile(fs::FS &fs, const char * path, const char * message) -{ - File file = fs.open(path, "w"); - if(!file){ - return; - } - file.print(message); - file.close(); -} - -// Send html file with template processing {{VAR}} -void sendHtmlFile(const char* filePath, AsyncWebServerRequest *request, String (*callback)(const String&)) -{ - ESP_LOGD(tag, "Sent file: %s", filePath); - File file = LittleFS.open(filePath, "r"); - const char* htmlFile = readFile(LittleFS, filePath); - - //String processedData = varReplace(htmlFile, htmlProcessor); - String processedData = varReplace(htmlFile, callback); - request->send(200, "text/html", processedData); -} - -const char* convertFileSize(const size_t bytes) { - static char fileSizeBuffer[16]; // PreAllocated buffer for the file size - - if (bytes < 1024) { - snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%d B", bytes); - } else if (bytes < 1024*1024) { - snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%.2f kB", static_cast(bytes) / 1024.0); - } else if (bytes < 1024*1024*1024) { - snprintf(fileSizeBuffer, sizeof(fileSizeBuffer), "%.2f MB", static_cast(bytes) / 1048576.0); - } else { - fileSizeBuffer[0] = '\0'; // Empty string if the file size is too large - } - - return fileSizeBuffer; -} - -// Callback template processor -String htmlProcessor(const String& var) -{ - if(var == "NAVBAR"){ return String("\n"); } - - if(var == "ALLOWED_EXTENSIONS_EDIT"){ return allowedExtensionsForEdit; } - - if(var == "FS_FREE_BYTES"){ return convertFileSize(LittleFS.totalBytes() - LittleFS.usedBytes()); } - - if(var == "FS_USED_BYTES"){ return convertFileSize(LittleFS.usedBytes()); } - - if(var == "FS_TOTAL_BYTES"){ return convertFileSize(LittleFS.totalBytes()); } - - if(var == "LISTED_FILES"){ - filesDropdownOptions = ""; // clear out - dirDropdownOptions = ""; // clear out - String directories[8]; - int dirCount = 0; - getAllDirectories(directories, dirCount); - - return listDir(directories, dirCount); - } - - if(var == "EDIT-DEL_FILES"){ return filesDropdownOptions; } - - if(var == "DIR_LIST"){ return dirDropdownOptions; } - - if(var == "SAVE_PATH_INPUT"){ - if(savePath == "/new.txt"){ - return String(""; - } - else{ - return String(""; - } - } - - if(var == "FIRM_VER"){ return FIRMWARE_VER; } - - return var; -} - -String HomeHtmlProcessor(const String& var) { - if(var == "NAVBAR"){ return String("\n"); } - - if (var == "APP_NAME") { - return sysProps.appName; - } - if (var == "OLED") { - return "No"; - } - if (var == "STRIP1") { - return (strip1) ? "Yes" : "No"; - } - if (var == "STRIP2") { - return (strip2) ? "Yes" : "No"; - } - if (var == "FRONT_LIGHT") { - return (animProps.frontLight.enabled) ? "Yes" : "No"; - } - if (var == "REAR_LIGHT") { - return (animProps.rearLight.enabled) ? "Yes" : "No"; - } - if (var == "FIRMWARE") { - return FIRMWARE_VER; - } - if (var == "BOOTH_T") { - return String(sysProps.t_sensor.temperature) + "F"; - } - if (var == "SETPOINT") { - return String(sysProps.t_sensor.Setpoint1) + "F"; - } - if (var == "FLASH_SIZE") { - return convertFileSize(ESP.getSketchSize()); - } - if (var == "FLASH_FREE") { - return convertFileSize(ESP.getFreeSketchSpace()); - } - if (var == "HEAP_SIZE") { - return convertFileSize(ESP.getHeapSize()); - } - if (var == "HEAP_FREE") { - return convertFileSize(ESP.getFreeHeap()); - } - if (var == "CPU_FREQ") { - return String(ESP.getCpuFreqMHz()) + "Mhz"; - } - if (var == "IP") { - return WiFi.localIP().toString(); - } - if (var == "MAC") { - return chipInfo.macStr; - } - if (var == "SSID") { - return WiFi.SSID(); - } - if (var == "RSSI") { - return String(WiFi.RSSI()); - } - if (var == "WIFI_CH") { - return String(WiFi.channel()); - } - if (var == "ENCRYP") { - return String(WiFi.encryptionType(0)); - } - if (var == "AP_SSID") { - return WiFi.softAPSSID(); - } - if (var == "AP_CLIENTS") { - return String(WiFi.softAPgetStationNum()); - } - if (var == "BLE") { - return (commMode == COMM_WIFI_AP_BLE) ? "Yes" : "No"; - } - if (var == "BLE_SSID") { - return (commMode == COMM_WIFI_AP_BLE) ? BLEDeviceName : ""; - } - if (var == "BLE_CLIENTS") { - return (BTDeviceConnected) ? "1" : "0"; - } - if (var == "AP_MAC") { - return getSoftAPMacAddress(); - } - - - // Return an empty string if the variable is not recognized - return var; -} - -String getSoftAPMacAddress() { - uint8_t mac[6]; - WiFi.softAPmacAddress(mac); - - String macString = ""; - for (int i = 0; i < 6; i++) { - macString += String(mac[i], HEX); - if (i < 5) macString += ":"; - } - return macString; -} - -// Finds segments between {{VAR}} and calls a callback function to replace VAR with new content -String varReplace(const String& input, String (*callback)(const String&)) { - if (input.isEmpty()) { - return input; - } - - String result; - int startPos = 0; - int start = input.indexOf("{{", startPos); - - while (start != -1) { - result += input.substring(startPos, start); - - int end = input.indexOf("}}", start + 2); - if (end == -1) { - break; - } - - String segment = input.substring(start + 2, end); - int segmentLength = segment.length(); - if (segmentLength <= 32) { - String replacement = callback(segment); - result += replacement; - } else { - result += input.substring(start, end + 2); // Include the original segment if it exceeds the limit - } - - startPos = end + 2; - start = input.indexOf("{{", startPos); - } - - result += input.substring(startPos); - return result; -} - -const char* getFileExtension(const char* filename) { - size_t dotPos = strlen(filename); - while (dotPos > 0 && filename[dotPos - 1] != '.') { - dotPos--; - } - - if (dotPos != 0 && dotPos < strlen(filename) - 1) { - return &filename[dotPos]; - } - - return ""; // Empty string if no extension found -} - -const char* getFileType(const char* ext) { - if (strcmp(ext, "png") == 0) { - return "image/png"; - } else if (strcmp(ext, "jpg") == 0 || strcmp(ext, "jpeg") == 0) { - return "image/jpeg"; - } else if (strcmp(ext, "gif") == 0) { - return "image/gif"; - } else if (strcmp(ext, "ico") == 0) { - return "image/x-icon"; - } else if (strcmp(ext, "txt") == 0) { - return "text/plain"; - } else if (strcmp(ext, "css") == 0) { - return "text/css"; - } else if (strcmp(ext, "htm") == 0 || strcmp(ext, "html") == 0) { - return "text/html"; - } else if (strcmp(ext, "js") == 0) { - return "text/javascript"; - } else if (strcmp(ext, "json") == 0) { - return "application/json"; - } else { - return ""; - } -} - -// Serial print firmware or file system update progress -void updateFirmwareProgress(size_t progress, size_t total) -{ - static int lastProg = -1; - int firmwareProgress = (progress * 100)/ total; - - if(firmwareProgress != lastProg){ - Serial.printf("Progress: %u%%\r", firmwareProgress); - lastProg = firmwareProgress; - //TODO Add buzzer tune while uploading firmware - //Buzzer_Play_Tune(TUNE_DOWNLOADING,1,true,false); - } -} - -