From 9641de1b12c3ae4980fc1c6b9a2f939a0b6d4934 Mon Sep 17 00:00:00 2001
From: Paula Scharf <paulascharf@gmx.de>
Date: Thu, 3 Jul 2025 15:22:07 +0200
Subject: [PATCH 01/34] feat(board): add senseBox Eye board

---
 boards.txt                                    | 190 ++++++++++++++++++
 variants/sensebox_eye/bootloader-tinyuf2.bin  | Bin 0 -> 22352 bytes
 .../sensebox_eye/partitions-16MB-tinyuf2.csv  |  10 +
 variants/sensebox_eye/pins_arduino.h          |  90 +++++++++
 variants/sensebox_eye/tinyuf2.bin             | Bin 0 -> 186912 bytes
 variants/sensebox_eye/variant.cpp             |  71 +++++++
 6 files changed, 361 insertions(+)
 create mode 100644 variants/sensebox_eye/bootloader-tinyuf2.bin
 create mode 100644 variants/sensebox_eye/partitions-16MB-tinyuf2.csv
 create mode 100644 variants/sensebox_eye/pins_arduino.h
 create mode 100644 variants/sensebox_eye/tinyuf2.bin
 create mode 100644 variants/sensebox_eye/variant.cpp

diff --git a/boards.txt b/boards.txt
index ac2b1a336e4..2363fe2a63b 100644
--- a/boards.txt
+++ b/boards.txt
@@ -41309,6 +41309,196 @@ sensebox_mcu_esp32s2.menu.EraseFlash.none.upload.erase_cmd=
 sensebox_mcu_esp32s2.menu.EraseFlash.all=Enabled
 sensebox_mcu_esp32s2.menu.EraseFlash.all.upload.erase_cmd=-e
 
+##############################################################
+# senseBox Eye
+
+sensebox_eye.name=senseBox Eye
+senseBox_eye.vid.0=0x303A
+senseBox_eye.pid.0=0x82D1
+senseBox_eye.vid.1=0x303A
+senseBox_eye.pid.1=0x82D2
+senseBox_eye.vid.2=0x303A
+senseBox_eye.pid.2=0x82D3
+
+sensebox_eye.bootloader.tool=esptool_py
+sensebox_eye.bootloader.tool.default=esptool_py
+
+sensebox_eye.upload.tool=esptool_py
+sensebox_eye.upload.tool.default=esptool_py
+sensebox_eye.upload.tool.network=esp_ota
+
+sensebox_eye.upload.maximum_size=1310720
+sensebox_eye.upload.maximum_data_size=327680
+sensebox_eye.upload.flags=
+sensebox_eye.upload.extra_flags=
+sensebox_eye.upload.use_1200bps_touch=true
+sensebox_eye.upload.wait_for_upload_port=true
+
+sensebox_eye.serial.disableDTR=true
+sensebox_eye.serial.disableRTS=true
+
+sensebox_eye.build.tarch=xtensa
+sensebox_eye.build.bootloader_addr=0x0
+sensebox_eye.build.target=esp32s3
+sensebox_eye.build.mcu=esp32s3
+sensebox_eye.build.core=esp32
+sensebox_eye.build.variant=sensebox_eye
+sensebox_eye.build.board=sensebox_eye
+
+sensebox_eye.build.usb_mode=0
+sensebox_eye.build.cdc_on_boot=1
+sensebox_eye.build.msc_on_boot=1
+sensebox_eye.build.dfu_on_boot=0
+sensebox_eye.build.f_cpu=240000000L
+sensebox_eye.build.flash_size=16MB (128Mb)
+sensebox_eye.build.flash_freq=80m
+sensebox_eye.build.flash_mode=dio
+sensebox_eye.build.boot=qio
+sensebox_eye.build.boot_freq=80m
+sensebox_eye.build.partitions=default_16MB
+sensebox_eye.build.defines=
+sensebox_eye.build.loop_core=
+sensebox_eye.build.event_core=
+sensebox_eye.build.psram_type=qspi
+sensebox_eye.build.memory_type={build.boot}_{build.psram_type}
+
+sensebox_eye.menu.JTAGAdapter.default=Disabled
+sensebox_eye.menu.JTAGAdapter.default.build.copy_jtag_files=0
+sensebox_eye.menu.JTAGAdapter.builtin=Integrated USB JTAG
+sensebox_eye.menu.JTAGAdapter.builtin.build.openocdscript=esp32s3-builtin.cfg
+sensebox_eye.menu.JTAGAdapter.builtin.build.copy_jtag_files=1
+sensebox_eye.menu.JTAGAdapter.external=FTDI Adapter
+sensebox_eye.menu.JTAGAdapter.external.build.openocdscript=esp32s3-ftdi.cfg
+sensebox_eye.menu.JTAGAdapter.external.build.copy_jtag_files=1
+sensebox_eye.menu.JTAGAdapter.bridge=ESP USB Bridge
+sensebox_eye.menu.JTAGAdapter.bridge.build.openocdscript=esp32s3-bridge.cfg
+sensebox_eye.menu.JTAGAdapter.bridge.build.copy_jtag_files=1
+
+sensebox_eye.menu.PSRAM.disabled=Disabled
+sensebox_eye.menu.PSRAM.disabled.build.defines=
+sensebox_eye.menu.PSRAM.disabled.build.psram_type=qspi
+sensebox_eye.menu.PSRAM.opi=OPI PSRAM
+sensebox_eye.menu.PSRAM.opi.build.defines=-DBOARD_HAS_PSRAM
+sensebox_eye.menu.PSRAM.opi.build.psram_type=opi
+
+sensebox_eye.menu.FlashMode.qio=QIO 80MHz
+sensebox_eye.menu.FlashMode.qio.build.flash_mode=dio
+sensebox_eye.menu.FlashMode.qio.build.boot=qio
+sensebox_eye.menu.FlashMode.qio.build.boot_freq=80m
+sensebox_eye.menu.FlashMode.qio.build.flash_freq=80m
+sensebox_eye.menu.FlashMode.dio=DIO 80MHz
+sensebox_eye.menu.FlashMode.dio.build.flash_mode=dio
+sensebox_eye.menu.FlashMode.dio.build.boot=dio
+sensebox_eye.menu.FlashMode.dio.build.boot_freq=80m
+sensebox_eye.menu.FlashMode.dio.build.flash_freq=80m
+
+sensebox_eye.menu.FlashSize.16M=16MB (128Mb)
+sensebox_eye.menu.FlashSize.16M.build.flash_size=16MB
+
+sensebox_eye.menu.LoopCore.1=Core 1
+sensebox_eye.menu.LoopCore.1.build.loop_core=-DARDUINO_RUNNING_CORE=1
+sensebox_eye.menu.LoopCore.0=Core 0
+sensebox_eye.menu.LoopCore.0.build.loop_core=-DARDUINO_RUNNING_CORE=0
+
+sensebox_eye.menu.EventsCore.1=Core 1
+sensebox_eye.menu.EventsCore.1.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=1
+sensebox_eye.menu.EventsCore.0=Core 0
+sensebox_eye.menu.EventsCore.0.build.event_core=-DARDUINO_EVENT_RUNNING_CORE=0
+
+sensebox_eye.menu.USBMode.hwcdc=Hardware CDC and JTAG
+sensebox_eye.menu.USBMode.hwcdc.build.usb_mode=1
+sensebox_eye.menu.USBMode.default=USB-OTG (TinyUSB)
+sensebox_eye.menu.USBMode.default.build.usb_mode=0
+
+sensebox_eye.menu.CDCOnBoot.default=Enabled
+sensebox_eye.menu.CDCOnBoot.default.build.cdc_on_boot=1
+sensebox_eye.menu.CDCOnBoot.cdc=Disabled
+sensebox_eye.menu.CDCOnBoot.cdc.build.cdc_on_boot=0
+
+sensebox_eye.menu.MSCOnBoot.default=Disabled
+sensebox_eye.menu.MSCOnBoot.default.build.msc_on_boot=0
+sensebox_eye.menu.MSCOnBoot.msc=Enabled (Requires USB-OTG Mode)
+sensebox_eye.menu.MSCOnBoot.msc.build.msc_on_boot=1
+
+sensebox_eye.menu.DFUOnBoot.default=Disabled
+sensebox_eye.menu.DFUOnBoot.default.build.dfu_on_boot=0
+sensebox_eye.menu.DFUOnBoot.dfu=Enabled (Requires USB-OTG Mode)
+sensebox_eye.menu.DFUOnBoot.dfu.build.dfu_on_boot=1
+
+sensebox_eye.menu.UploadMode.default=UART0 / Hardware CDC
+sensebox_eye.menu.UploadMode.default.upload.use_1200bps_touch=false
+sensebox_eye.menu.UploadMode.default.upload.wait_for_upload_port=false
+sensebox_eye.menu.UploadMode.cdc=USB-OTG CDC (TinyUSB)
+sensebox_eye.menu.UploadMode.cdc.upload.use_1200bps_touch=true
+sensebox_eye.menu.UploadMode.cdc.upload.wait_for_upload_port=true
+
+sensebox_eye.menu.PartitionScheme.default_16MB=Default (6.25MB APP/3.43MB SPIFFS)
+sensebox_eye.menu.PartitionScheme.default_16MB.build.partitions=default_16MB
+sensebox_eye.menu.PartitionScheme.default_16MB.upload.maximum_size=6553600
+sensebox_eye.menu.PartitionScheme.large_spiffs=Large SPIFFS (4.5MB APP/6.93MB SPIFFS)
+sensebox_eye.menu.PartitionScheme.large_spiffs.build.partitions=large_spiffs_16MB
+sensebox_eye.menu.PartitionScheme.large_spiffs.upload.maximum_size=4718592
+sensebox_eye.menu.PartitionScheme.app3M_fat9M_16MB=FFAT (3MB APP/9MB FATFS)
+sensebox_eye.menu.PartitionScheme.app3M_fat9M_16MB.build.partitions=app3M_fat9M_16MB
+sensebox_eye.menu.PartitionScheme.app3M_fat9M_16MB.upload.maximum_size=3145728
+sensebox_eye.menu.PartitionScheme.fatflash=Large FFAT (2MB APP/12.5MB FATFS)
+sensebox_eye.menu.PartitionScheme.fatflash.build.partitions=ffat
+sensebox_eye.menu.PartitionScheme.fatflash.upload.maximum_size=2097152
+sensebox_eye.menu.PartitionScheme.tinyuf2=TinyUF2 Compatibility (2MB APP/12MB FFAT)
+sensebox_eye.menu.PartitionScheme.tinyuf2.build.custom_bootloader=bootloader_tinyuf2
+sensebox_eye.menu.PartitionScheme.tinyuf2.build.custom_partitions=partitions_tinyuf2
+sensebox_eye.menu.PartitionScheme.tinyuf2.upload.maximum_size=2097152
+sensebox_eye.menu.PartitionScheme.tinyuf2.upload.extra_flags=0x410000 "{runtime.platform.path}/variants/{build.variant}/tinyuf2.bin"
+sensebox_eye.menu.PartitionScheme.gen4esp32scheme4=Huge App (16MB APP)
+sensebox_eye.menu.PartitionScheme.gen4esp32scheme4.build.custom_partitions=gen4esp32_16MBapp
+sensebox_eye.menu.PartitionScheme.gen4esp32scheme4.upload.maximum_size=16646144
+
+sensebox_eye.menu.CPUFreq.240=240MHz (WiFi)
+sensebox_eye.menu.CPUFreq.240.build.f_cpu=240000000L
+sensebox_eye.menu.CPUFreq.160=160MHz (WiFi)
+sensebox_eye.menu.CPUFreq.160.build.f_cpu=160000000L
+sensebox_eye.menu.CPUFreq.80=80MHz (WiFi)
+sensebox_eye.menu.CPUFreq.80.build.f_cpu=80000000L
+sensebox_eye.menu.CPUFreq.40=40MHz
+sensebox_eye.menu.CPUFreq.40.build.f_cpu=40000000L
+sensebox_eye.menu.CPUFreq.20=20MHz
+sensebox_eye.menu.CPUFreq.20.build.f_cpu=20000000L
+sensebox_eye.menu.CPUFreq.10=10MHz
+sensebox_eye.menu.CPUFreq.10.build.f_cpu=10000000L
+
+sensebox_eye.menu.UploadSpeed.921600=921600
+sensebox_eye.menu.UploadSpeed.921600.upload.speed=921600
+sensebox_eye.menu.UploadSpeed.115200=115200
+sensebox_eye.menu.UploadSpeed.115200.upload.speed=115200
+sensebox_eye.menu.UploadSpeed.256000.windows=256000
+sensebox_eye.menu.UploadSpeed.256000.upload.speed=256000
+sensebox_eye.menu.UploadSpeed.230400.windows.upload.speed=256000
+sensebox_eye.menu.UploadSpeed.230400=230400
+sensebox_eye.menu.UploadSpeed.230400.upload.speed=230400
+sensebox_eye.menu.UploadSpeed.460800.linux=460800
+sensebox_eye.menu.UploadSpeed.460800.macosx=460800
+sensebox_eye.menu.UploadSpeed.460800.upload.speed=460800
+sensebox_eye.menu.UploadSpeed.512000.windows=512000
+sensebox_eye.menu.UploadSpeed.512000.upload.speed=512000
+
+sensebox_eye.menu.DebugLevel.none=None
+sensebox_eye.menu.DebugLevel.none.build.code_debug=0
+sensebox_eye.menu.DebugLevel.error=Error
+sensebox_eye.menu.DebugLevel.error.build.code_debug=1
+sensebox_eye.menu.DebugLevel.warn=Warn
+sensebox_eye.menu.DebugLevel.warn.build.code_debug=2
+sensebox_eye.menu.DebugLevel.info=Info
+sensebox_eye.menu.DebugLevel.info.build.code_debug=3
+sensebox_eye.menu.DebugLevel.debug=Debug
+sensebox_eye.menu.DebugLevel.debug.build.code_debug=4
+sensebox_eye.menu.DebugLevel.verbose=Verbose
+sensebox_eye.menu.DebugLevel.verbose.build.code_debug=5
+
+sensebox_eye.menu.EraseFlash.none=Disabled
+sensebox_eye.menu.EraseFlash.none.upload.erase_cmd=
+sensebox_eye.menu.EraseFlash.all=Enabled
+sensebox_eye.menu.EraseFlash.all.upload.erase_cmd=-e
+
 ##############################################################
 
 nano_nora.name=Arduino Nano ESP32
diff --git a/variants/sensebox_eye/bootloader-tinyuf2.bin b/variants/sensebox_eye/bootloader-tinyuf2.bin
new file mode 100644
index 0000000000000000000000000000000000000000..c7676c718f2383a78785da38dcffde52ca67eab0
GIT binary patch
diff --git a/variants/sensebox_eye/partitions-16MB-tinyuf2.csv b/variants/sensebox_eye/partitions-16MB-tinyuf2.csv
new file mode 100644
index 00000000000..960f3fbbd71
--- /dev/null
+++ b/variants/sensebox_eye/partitions-16MB-tinyuf2.csv
@@ -0,0 +1,10 @@
+# ESP-IDF Partition Table
+# Name,   Type, SubType, Offset,  Size, Flags
+# bootloader.bin,,          0x1000, 32K
+# partition table,          0x8000, 4K
+nvs,      data, nvs,      0x9000,  20K,
+otadata,  data, ota,      0xe000,  8K,
+ota_0,    0,    ota_0,   0x10000,  2048K,
+ota_1,    0,    ota_1,  0x210000,  2048K,
+uf2,      app,  factory,0x410000,  256K,
+ffat,     data, fat,    0x450000,  11968K,
\ No newline at end of file
diff --git a/variants/sensebox_eye/pins_arduino.h b/variants/sensebox_eye/pins_arduino.h
new file mode 100644
index 00000000000..583cb38283e
--- /dev/null
+++ b/variants/sensebox_eye/pins_arduino.h
@@ -0,0 +1,90 @@
+#ifndef Pins_Arduino_h
+#define Pins_Arduino_h
+
+#include <stdint.h>
+
+#define USB_VID          0x303A
+#define USB_PID          0x81B8
+#define USB_MANUFACTURER "senseBox"
+#define USB_PRODUCT      "Eye ESP32S3"
+#define USB_SERIAL       ""  // Empty string for MAC address
+
+// Default USB FirmwareMSC Settings
+#define USB_FW_MSC_VENDOR_ID        "senseBox"        // max 8 chars
+#define USB_FW_MSC_PRODUCT_ID       "Eye ESP32S3"  // max 16 chars
+#define USB_FW_MSC_PRODUCT_REVISION "1.00"            // max 4 chars
+#define USB_FW_MSC_VOLUME_NAME      "senseBox"        // max 11 chars
+#define USB_FW_MSC_SERIAL_NUMBER    0x00000000
+
+#define PIN_RGB_LED 45  // RGB LED
+#define RGBLED_PIN  45  // RGB LED
+#define PIN_LED   45
+#define RGBLED_NUM  1  // number of RGB LEDs
+
+// Default I2C QWIIC-Ports
+static const uint8_t SDA = 2;
+static const uint8_t SCL = 1;
+#define PIN_QWIIC_SDA 2
+#define PIN_QWIIC_SCL 1
+
+// IO Pins
+#define PIN_IO14   14
+static const uint8_t A14 = PIN_IO14; // Analog
+static const uint8_t D14 = PIN_IO14; // Digital
+static const uint8_t T14 = PIN_IO14; // Touch
+#define PIN_IO48   48
+static const uint8_t A48 = PIN_IO48; // Analog
+static const uint8_t D48 = PIN_IO48; // Digital
+static const uint8_t T48 = PIN_IO48; // Touch
+
+// Button
+#define PIN_BUTTON 47
+
+// UART Port
+static const uint8_t TX = 43;
+static const uint8_t RX = 44;
+#define PIN_UART_TXD    43
+#define PIN_UART_RXD    44
+#define PIN_UART_ENABLE 26
+
+// SD-Card
+#define MISO      40
+#define MOSI      38
+#define SCK       39
+#define SS        41
+#define SD_ENABLE 3
+
+#define PIN_SD_MISO   40
+#define PIN_SD_MOSI   38
+#define PIN_SD_SCLK   39
+#define PIN_SD_CS     41
+#define PIN_SD_ENABLE 3
+
+// USB
+#define PIN_USB_DM 19
+#define PIN_USB_DP 20
+
+// Camera
+#define PWDN_GPIO_NUM  46
+#define RESET_GPIO_NUM -1
+#define XCLK_GPIO_NUM  15
+#define SIOD_GPIO_NUM  4
+#define SIOC_GPIO_NUM  5
+
+#define Y9_GPIO_NUM    16
+#define Y8_GPIO_NUM    17
+#define Y7_GPIO_NUM    18
+#define Y6_GPIO_NUM    12
+#define Y5_GPIO_NUM    10
+#define Y4_GPIO_NUM    8
+#define Y3_GPIO_NUM    9
+#define Y2_GPIO_NUM    11
+#define VSYNC_GPIO_NUM 6
+#define HREF_GPIO_NUM  7
+#define PCLK_GPIO_NUM  13
+
+// LoRa
+#define LORA_TX 43
+#define LORA_RX 44
+
+#endif /* Pins_Arduino_h */
\ No newline at end of file
diff --git a/variants/sensebox_eye/tinyuf2.bin b/variants/sensebox_eye/tinyuf2.bin
new file mode 100644
index 0000000000000000000000000000000000000000..6b0fb1bcd0417ce9175fc75bf09b49f7516ab078
GIT binary patch
diff --git a/variants/sensebox_eye/variant.cpp b/variants/sensebox_eye/variant.cpp
new file mode 100644
index 00000000000..42269d11357
--- /dev/null
+++ b/variants/sensebox_eye/variant.cpp
@@ -0,0 +1,71 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Ha Thach (tinyusb.org) for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "esp32-hal-gpio.h"
+#include "pins_arduino.h"
+#include "driver/rmt_tx.h"
+#include "esp_log.h"
+
+extern "C" {
+
+void initVariant(void) {
+  rmt_channel_handle_t led_chan = NULL;
+  rmt_tx_channel_config_t tx_chan_config = {};
+  tx_chan_config.clk_src = RMT_CLK_SRC_DEFAULT;
+  tx_chan_config.resolution_hz = 10 * 1000 * 1000;
+  tx_chan_config.mem_block_symbols = 64;
+  tx_chan_config.trans_queue_depth = 4;
+  tx_chan_config.gpio_num = (gpio_num_t)PIN_LED;
+  tx_chan_config.flags.invert_out = false;
+  tx_chan_config.flags.with_dma = false;
+  ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan));
+
+  // WS2812 encoder config (available in `esp-rmt`)
+  rmt_encoder_handle_t ws2812_encoder = NULL;
+  rmt_bytes_encoder_config_t bytes_encoder_config = {
+    .bit0 = { .duration0 = 4, .level0 = 1, .duration1 = 9, .level1 = 0 },
+    .bit1 = { .duration0 = 8, .level0 = 1, .duration1 = 5, .level1 = 0 },
+    .flags = { .msb_first = true }
+  };
+  ESP_ERROR_CHECK(rmt_new_bytes_encoder(&bytes_encoder_config, &ws2812_encoder));
+
+  ESP_ERROR_CHECK(rmt_enable(led_chan));
+
+  // WS2812 GRB data (green pixel)
+  uint8_t pixel[3] = { 0x10, 0x00, 0x00 }; // green
+  rmt_transmit_config_t tx_config = {
+    .loop_count = 0
+  };
+  ESP_ERROR_CHECK(rmt_transmit(led_chan, ws2812_encoder, pixel, sizeof(pixel), &tx_config));
+  rmt_tx_wait_all_done(led_chan, portMAX_DELAY);
+
+  // Wait a moment
+  delay(50);
+
+  // Turn LED off
+  uint8_t pixel_off[3] = { 0x00, 0x00, 0x00 };
+  ESP_ERROR_CHECK(rmt_transmit(led_chan, ws2812_encoder, pixel_off, sizeof(pixel_off), &tx_config));
+  rmt_tx_wait_all_done(led_chan, portMAX_DELAY);
+}
+}

From 6a33f0bfc137a664111e5bbce62c05511f9727a2 Mon Sep 17 00:00:00 2001
From: Paula Scharf <paulascharf@gmx.de>
Date: Wed, 9 Jul 2025 16:52:51 +0200
Subject: [PATCH 02/34] fix(board): add APOTA description comments

---
 variants/sensebox_mcu_esp32s2/APOTA.ino | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/variants/sensebox_mcu_esp32s2/APOTA.ino b/variants/sensebox_mcu_esp32s2/APOTA.ino
index 5f683752abc..afb741499b2 100644
--- a/variants/sensebox_mcu_esp32s2/APOTA.ino
+++ b/variants/sensebox_mcu_esp32s2/APOTA.ino
@@ -1,3 +1,7 @@
+// APOTA is a arduino fallback sketch that is written to OTA1_Partition. 
+// APOTA opens an access point which waits to receive a .binfile on /sketch. 
+// After succesful upload, the file is written to OTA0_Partition and the microcontroller reboots to the newly uploaded sketch.
+
 #define DISPLAY_ENABLED
 
 #include <WiFi.h>

From 76210797ed11288bfd3c6c27122f0103562196d3 Mon Sep 17 00:00:00 2001
From: Paula Scharf <paulascharf@gmx.de>
Date: Wed, 9 Jul 2025 16:53:33 +0200
Subject: [PATCH 03/34] fix(board): add APOTA to senseBox Eye

---
 boards.txt                        |   2 +-
 variants/sensebox_eye/APOTA.bin   | Bin 0 -> 976464 bytes
 variants/sensebox_eye/APOTA.ino   | 287 ++++++++++++++++++++++++++++++
 variants/sensebox_eye/variant.cpp |  65 +++++--
 4 files changed, 343 insertions(+), 11 deletions(-)
 create mode 100644 variants/sensebox_eye/APOTA.bin
 create mode 100644 variants/sensebox_eye/APOTA.ino

diff --git a/boards.txt b/boards.txt
index 2363fe2a63b..faa7f94a994 100644
--- a/boards.txt
+++ b/boards.txt
@@ -41448,7 +41448,7 @@ sensebox_eye.menu.PartitionScheme.tinyuf2=TinyUF2 Compatibility (2MB APP/12MB FF
 sensebox_eye.menu.PartitionScheme.tinyuf2.build.custom_bootloader=bootloader_tinyuf2
 sensebox_eye.menu.PartitionScheme.tinyuf2.build.custom_partitions=partitions_tinyuf2
 sensebox_eye.menu.PartitionScheme.tinyuf2.upload.maximum_size=2097152
-sensebox_eye.menu.PartitionScheme.tinyuf2.upload.extra_flags=0x410000 "{runtime.platform.path}/variants/{build.variant}/tinyuf2.bin"
+sensebox_eye.menu.PartitionScheme.tinyuf2.upload.extra_flags=0x410000 "{runtime.platform.path}/variants/{build.variant}/tinyuf2.bin" 0x210000 "{runtime.platform.path}/variants/{build.variant}/APOTA.bin"
 sensebox_eye.menu.PartitionScheme.gen4esp32scheme4=Huge App (16MB APP)
 sensebox_eye.menu.PartitionScheme.gen4esp32scheme4.build.custom_partitions=gen4esp32_16MBapp
 sensebox_eye.menu.PartitionScheme.gen4esp32scheme4.upload.maximum_size=16646144
diff --git a/variants/sensebox_eye/APOTA.bin b/variants/sensebox_eye/APOTA.bin
new file mode 100644
index 0000000000000000000000000000000000000000..571336d378a9aaee97e074142d0e73cad85eacc9
GIT binary patch
diff --git a/variants/sensebox_eye/APOTA.ino b/variants/sensebox_eye/APOTA.ino
new file mode 100644
index 00000000000..afb741499b2
--- /dev/null
+++ b/variants/sensebox_eye/APOTA.ino
@@ -0,0 +1,287 @@
+// APOTA is a arduino fallback sketch that is written to OTA1_Partition. 
+// APOTA opens an access point which waits to receive a .binfile on /sketch. 
+// After succesful upload, the file is written to OTA0_Partition and the microcontroller reboots to the newly uploaded sketch.
+
+#define DISPLAY_ENABLED
+
+#include <WiFi.h>
+#include <WebServer.h>
+#include <ESPmDNS.h>
+#include <WiFiAP.h>
+#include <Update.h>
+#include <Wire.h>
+#ifdef DISPLAY_ENABLED
+#define SCREEN_WIDTH  128
+#define SCREEN_HEIGHT 64
+#define OLED_RESET    -1
+#include <Adafruit_GFX.h>
+#include <Adafruit_SSD1306.h>
+Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
+#include <Adafruit_NeoPixel.h>
+Adafruit_NeoPixel rgb_led_1 = Adafruit_NeoPixel(1, 1, NEO_GRB + NEO_KHZ800);
+
+#endif
+#include "esp_partition.h"
+#include "esp_ota_ops.h"
+#include "esp_system.h"
+
+String ssid;
+uint8_t mac[6];
+
+// Create an instance of the server
+WebServer server(80);
+bool displayEnabled;
+
+const int BUTTON_PIN = 0;                       // GPIO for the button
+volatile unsigned long lastPressTime = 0;       // Time of last button press
+volatile bool doublePressDetected = false;      // Flag for double press
+const unsigned long doublePressInterval = 500;  // Max. time (in ms) between two presses for double press
+volatile int pressCount = 0;                    // Counts the button presses
+
+const unsigned char epd_bitmap_wifi[] PROGMEM = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0xff, 0x00, 0x00,
+  0x00, 0x3f, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x7c, 0x00, 0x03, 0xe0, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xf0, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x78, 0x00,
+  0x03, 0xc0, 0x00, 0x00, 0x38, 0x00, 0x07, 0x80, 0x00, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x7f, 0xe0, 0x0e, 0x00,
+  0x0c, 0x01, 0xff, 0xf0, 0x06, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x02, 0x00, 0x00, 0x0f, 0x80, 0x3e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
+  0x00, 0x1c, 0x00, 0x07, 0x80, 0x00, 0x00, 0x38, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x70, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x70, 0x00, 0x00, 0xc0, 0x00,
+  0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00,
+  0x00, 0x01, 0xe0, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x78, 0x00, 0x00, 0x00, 0x03, 0x80, 0x38, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'checkmark', 44x44px
+const unsigned char epd_bitmap_checkmark[] PROGMEM = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xf0, 0x00, 0x00,
+  0x00, 0x0f, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x0f, 0x83, 0xc0, 0x00, 0x00, 0x00, 0x07, 0xc7, 0x80, 0x00, 0x00, 0x00, 0x03, 0xef, 0x00, 0x00, 0x00,
+  0x00, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+void IRAM_ATTR handleButtonPress() {
+  unsigned long currentTime = millis();  // Get current time
+
+  // Debounce: If the current press is too close to the last one, ignore it
+  if (currentTime - lastPressTime > 50) {
+    pressCount++;  // Count the button press
+
+    // Check if this is the second press within the double-press interval
+    if (pressCount == 2 && (currentTime - lastPressTime <= doublePressInterval)) {
+      doublePressDetected = true;  // Double press detected
+      pressCount = 0;              // Reset counter
+    }
+
+    lastPressTime = currentTime;  // Update the time of the last press
+  }
+}
+
+// Function to switch the boot partition to OTA1
+void setBootPartitionToOTA0() {
+  const esp_partition_t *ota0_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL);
+
+  if (ota0_partition) {
+    // Set OTA1 as new boot partition
+    esp_ota_set_boot_partition(ota0_partition);
+    Serial.println("Boot partition changed to OTA0. Restarting...");
+
+    // Restart to boot from the new partition
+    esp_restart();
+  } else {
+    Serial.println("OTA1 partition not found!");
+  }
+}
+
+void setupDisplay() {
+  displayEnabled = display.begin(SSD1306_SWITCHCAPVCC, 0x3D);
+  if (displayEnabled) {
+    display.display();
+    delay(100);
+    display.clearDisplay();
+  }
+}
+
+void displayStatusBar(int progress) {
+  display.clearDisplay();
+  display.setCursor(24, 8);
+  display.println("Sketch wird");
+  display.setCursor(22, 22);
+  display.println("hochgeladen!");
+
+  display.fillRect(0, SCREEN_HEIGHT - 24, SCREEN_WIDTH - 4, 8, BLACK);  // Clear status bar area
+  display.drawRect(0, SCREEN_HEIGHT - 24, SCREEN_WIDTH - 4, 8, WHITE);  // Draw border
+  int filledWidth = (progress * SCREEN_WIDTH - 4) / 100;                // Calculate progress width
+  display.fillRect(1, SCREEN_HEIGHT - 23, filledWidth - 4, 6, WHITE);   // Fill progress bar
+
+  display.setCursor((SCREEN_WIDTH / 2) - 12, SCREEN_HEIGHT - 10);
+  display.setTextSize(1);
+  display.setTextColor(WHITE, BLACK);
+  display.print(progress);
+  display.println(" %");
+  display.display();
+}
+
+void displayWelcomeScreen() {
+  display.clearDisplay();
+
+  // Draw WiFi symbol
+  display.drawBitmap(0, 12, epd_bitmap_wifi, 44, 44, WHITE);
+
+  // Display SSID text
+  display.setCursor(40, 13);
+  display.setTextSize(1);
+  display.setTextColor(WHITE, BLACK);
+  display.println("Verbinde dich");  // "Connect"
+  display.setCursor(60, 27);
+  display.println("mit:");  // "with"
+
+  // Display SSID
+  display.setCursor(40, 43);
+  display.setTextSize(1);  // Larger text for SSID
+  display.print(ssid);
+
+  display.display();
+}
+
+void displaySuccessScreen() {
+  display.clearDisplay();
+
+  // Draw WiFi symbol
+  display.drawBitmap(0, 12, epd_bitmap_checkmark, 44, 44, WHITE);
+
+  // Display SSID text
+  display.setCursor(48, 22);
+  display.setTextSize(1);
+  display.setTextColor(WHITE, BLACK);
+  display.println("Erfolgreich");  // "Successfully"
+  display.setCursor(48, 36);
+  display.println("hochgeladen!");  // "uploaded!"
+
+  display.display();
+}
+
+void wipeDisplay() {
+  display.clearDisplay();
+  display.println("");
+  display.display();
+}
+
+void setupWiFi() {
+  WiFi.macAddress(mac);
+  char macLastFour[5];
+  snprintf(macLastFour, sizeof(macLastFour), "%02X%02X", mac[4], mac[5]);
+  ssid = "senseBox:" + String(macLastFour);
+
+  // Define the IP address, gateway, and subnet mask
+  IPAddress local_IP(192, 168, 1, 1);  // The new IP address
+  IPAddress gateway(192, 168, 1, 1);   // Gateway address (can be the same as the AP's IP)
+  IPAddress subnet(255, 255, 255, 0);  // Subnet mask
+
+  // Set the IP address, gateway, and subnet mask of the access point
+  WiFi.softAPConfig(local_IP, gateway, subnet);
+
+  // Start the access point
+  WiFi.softAP(ssid.c_str());
+}
+
+void setupOTA() {
+  // Handle updating process
+  server.on(
+    "/sketch", HTTP_POST,
+    []() {
+      server.sendHeader("Connection", "close");
+      server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
+      ESP.restart();
+    },
+    []() {
+      HTTPUpload &upload = server.upload();
+
+      if (upload.status == UPLOAD_FILE_START) {
+        Serial.setDebugOutput(true);
+        size_t fsize = UPDATE_SIZE_UNKNOWN;
+        if (server.clientContentLength() > 0) {
+          fsize = server.clientContentLength();
+        }
+        Serial.printf("Receiving Update: %s, Size: %d\n", upload.filename.c_str(), fsize);
+
+        Serial.printf("Update: %s\n", upload.filename.c_str());
+        if (!Update.begin(fsize)) {  //start with max available size
+          Update.printError(Serial);
+        }
+      } else if (upload.status == UPLOAD_FILE_WRITE) {
+        /* flashing firmware to ESP*/
+        if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
+          Update.printError(Serial);
+        } else {
+          int progress = (Update.progress() * 100) / Update.size();
+          displayStatusBar(progress);  // Update progress on status bar
+        }
+      } else if (upload.status == UPLOAD_FILE_END) {
+        if (Update.end(true)) {  //true to set the size to the current progress
+          displaySuccessScreen();
+          delay(3000);
+          wipeDisplay();
+        } else {
+          Update.printError(Serial);
+        }
+        Serial.setDebugOutput(false);
+      }
+      yield();
+    }
+  );
+}
+
+void setup() {
+  // Start Serial communication
+  Serial.begin(115200);
+  rgb_led_1.begin();
+  rgb_led_1.setBrightness(30);
+  rgb_led_1.setPixelColor(0, rgb_led_1.Color(51, 51, 255));
+  rgb_led_1.show();
+
+  // Configure button pin as input
+  pinMode(BUTTON_PIN, INPUT_PULLUP);
+
+  // Interrupt for the button
+  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), handleButtonPress, FALLING);
+
+#ifdef DISPLAY_ENABLED
+  setupDisplay();
+#endif
+  setupWiFi();
+  // Set the ESP32 as an access point
+  setupOTA();
+  server.begin();
+}
+
+void loop() {
+  // Handle client requests
+  server.handleClient();
+
+#ifdef DISPLAY_ENABLED
+  displayWelcomeScreen();
+#endif
+
+  if (doublePressDetected) {
+    Serial.println("Doppeldruck erkannt!");  // "Double press detected!"
+    setBootPartitionToOTA0();
+#ifdef DISPLAY_ENABLED
+    display.setCursor(0, 0);
+    display.setTextSize(1);
+    display.setTextColor(WHITE, BLACK);
+    display.println("");
+    display.display();
+    delay(50);
+#endif
+    // Restart to boot from the new partition
+    esp_restart();
+  }
+}
diff --git a/variants/sensebox_eye/variant.cpp b/variants/sensebox_eye/variant.cpp
index 42269d11357..c802c614cc1 100644
--- a/variants/sensebox_eye/variant.cpp
+++ b/variants/sensebox_eye/variant.cpp
@@ -26,9 +26,25 @@
 #include "pins_arduino.h"
 #include "driver/rmt_tx.h"
 #include "esp_log.h"
+#include "esp_partition.h"
+#include "esp_system.h"
+#include "esp_ota_ops.h"
 
 extern "C" {
 
+void blinkLED(uint8_t color[3], rmt_channel_handle_t led_chan, rmt_encoder_handle_t ws2812_encoder, rmt_transmit_config_t tx_config) {
+  ESP_ERROR_CHECK(rmt_transmit(led_chan, ws2812_encoder, color, sizeof(color), &tx_config));
+  rmt_tx_wait_all_done(led_chan, portMAX_DELAY);
+
+  // Wait a moment
+  delay(50);
+
+  // Turn LED off
+  uint8_t pixel_off[3] = { 0x00, 0x00, 0x00 };
+  ESP_ERROR_CHECK(rmt_transmit(led_chan, ws2812_encoder, pixel_off, sizeof(pixel_off), &tx_config));
+  rmt_tx_wait_all_done(led_chan, portMAX_DELAY);
+}
+
 void initVariant(void) {
   rmt_channel_handle_t led_chan = NULL;
   rmt_tx_channel_config_t tx_chan_config = {};
@@ -52,20 +68,49 @@ void initVariant(void) {
 
   ESP_ERROR_CHECK(rmt_enable(led_chan));
 
-  // WS2812 GRB data (green pixel)
-  uint8_t pixel[3] = { 0x10, 0x00, 0x00 }; // green
   rmt_transmit_config_t tx_config = {
     .loop_count = 0
   };
-  ESP_ERROR_CHECK(rmt_transmit(led_chan, ws2812_encoder, pixel, sizeof(pixel), &tx_config));
-  rmt_tx_wait_all_done(led_chan, portMAX_DELAY);
 
-  // Wait a moment
-  delay(50);
+  uint8_t pixel[3] = { 0x10, 0x00, 0x00 }; // green
+  blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
 
-  // Turn LED off
-  uint8_t pixel_off[3] = { 0x00, 0x00, 0x00 };
-  ESP_ERROR_CHECK(rmt_transmit(led_chan, ws2812_encoder, pixel_off, sizeof(pixel_off), &tx_config));
-  rmt_tx_wait_all_done(led_chan, portMAX_DELAY);
+  // define button pin
+  pinMode(0, INPUT_PULLUP);
+
+  // keep button pressed
+  unsigned long pressStartTime = 0;
+  bool buttonPressed = false;
+
+  // Wait 3.5 seconds for the button to be pressed
+  unsigned long startTime = millis();
+
+  // Check if button is pressed
+  while (millis() - startTime < 3500) {
+    if (digitalRead(0) == LOW) {
+      if (!buttonPressed) {
+        // The button was pressed
+        buttonPressed = true;
+      }
+    } else if (buttonPressed) {
+      // When the button is pressed and then released, boot into the OTA1 partition
+      const esp_partition_t *ota1_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL);
+
+      if (ota1_partition) {
+        esp_err_t err = esp_ota_set_boot_partition(ota1_partition);
+        if (err == ESP_OK) {
+          uint8_t pixel[3] = { 0x00, 0x00, 0x10 }; // blue
+          blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
+          esp_restart();  // restart, to boot OTA1 partition
+        } else {
+          uint8_t pixel[3] = { 0x00, 0x10, 0x00 }; // red
+          blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
+          ESP_LOGE("OTA", "Error setting OTA1 partition: %s", esp_err_to_name(err));
+        }
+      }
+      // Abort after releasing the button
+      break;
+    }
+  }
 }
 }

From f330585717ee9758b15a0ae8fe939967937a4539 Mon Sep 17 00:00:00 2001
From: Paula Scharf <paulascharf@gmx.de>
Date: Tue, 15 Jul 2025 11:14:26 +0200
Subject: [PATCH 04/34] feat(board): update PID

---
 variants/sensebox_eye/pins_arduino.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/variants/sensebox_eye/pins_arduino.h b/variants/sensebox_eye/pins_arduino.h
index 583cb38283e..99984dbc6a4 100644
--- a/variants/sensebox_eye/pins_arduino.h
+++ b/variants/sensebox_eye/pins_arduino.h
@@ -4,7 +4,7 @@
 #include <stdint.h>
 
 #define USB_VID          0x303A
-#define USB_PID          0x81B8
+#define USB_PID          0x82D1
 #define USB_MANUFACTURER "senseBox"
 #define USB_PRODUCT      "Eye ESP32S3"
 #define USB_SERIAL       ""  // Empty string for MAC address

From cdf606af5f4424a2ea568734be290e00d906c538 Mon Sep 17 00:00:00 2001
From: Paula Scharf <paulascharf@gmx.de>
Date: Tue, 15 Jul 2025 16:45:03 +0200
Subject: [PATCH 05/34] feat(board): updated tinyuf2 bins

---
 variants/sensebox_eye/bootloader-tinyuf2.bin | Bin 22352 -> 23120 bytes
 variants/sensebox_eye/tinyuf2.bin            | Bin 186912 -> 193056 bytes
 2 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/variants/sensebox_eye/bootloader-tinyuf2.bin b/variants/sensebox_eye/bootloader-tinyuf2.bin
index c7676c718f2383a78785da38dcffde52ca67eab0..7a83be05436d3ea295c2a06e4ffd5a814c145f42 100644
GIT binary patch
diff --git a/variants/sensebox_eye/tinyuf2.bin b/variants/sensebox_eye/tinyuf2.bin
index 6b0fb1bcd0417ce9175fc75bf09b49f7516ab078..67c00aa39f0644371b2aeac5b2cbd898970a4481 100644
GIT binary patch

From 439bbb8391f6cf8db626cf1190ee3a36ec3479f1 Mon Sep 17 00:00:00 2001
From: Paula Scharf <paulascharf@gmx.de>
Date: Thu, 17 Jul 2025 16:15:10 +0200
Subject: [PATCH 06/34] feat(board): use additional button for APOTA

---
 variants/sensebox_eye/variant.cpp | 50 +++++++++++--------------------
 1 file changed, 17 insertions(+), 33 deletions(-)

diff --git a/variants/sensebox_eye/variant.cpp b/variants/sensebox_eye/variant.cpp
index c802c614cc1..1eef839494e 100644
--- a/variants/sensebox_eye/variant.cpp
+++ b/variants/sensebox_eye/variant.cpp
@@ -72,45 +72,29 @@ void initVariant(void) {
     .loop_count = 0
   };
 
-  uint8_t pixel[3] = { 0x10, 0x00, 0x00 }; // green
-  blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
-
   // define button pin
-  pinMode(0, INPUT_PULLUP);
-
-  // keep button pressed
-  unsigned long pressStartTime = 0;
-  bool buttonPressed = false;
-
-  // Wait 3.5 seconds for the button to be pressed
-  unsigned long startTime = millis();
+  pinMode(47, INPUT_PULLUP);
 
   // Check if button is pressed
-  while (millis() - startTime < 3500) {
-    if (digitalRead(0) == LOW) {
-      if (!buttonPressed) {
-        // The button was pressed
-        buttonPressed = true;
-      }
-    } else if (buttonPressed) {
-      // When the button is pressed and then released, boot into the OTA1 partition
-      const esp_partition_t *ota1_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL);
+  if (digitalRead(47) == LOW) {
+    // When the button is pressed and then released, boot into the OTA1 partition
+    const esp_partition_t *ota1_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL);
 
-      if (ota1_partition) {
-        esp_err_t err = esp_ota_set_boot_partition(ota1_partition);
-        if (err == ESP_OK) {
-          uint8_t pixel[3] = { 0x00, 0x00, 0x10 }; // blue
-          blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
-          esp_restart();  // restart, to boot OTA1 partition
-        } else {
-          uint8_t pixel[3] = { 0x00, 0x10, 0x00 }; // red
-          blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
-          ESP_LOGE("OTA", "Error setting OTA1 partition: %s", esp_err_to_name(err));
-        }
+    if (ota1_partition) {
+      esp_err_t err = esp_ota_set_boot_partition(ota1_partition);
+      if (err == ESP_OK) {
+        uint8_t pixel[3] = { 0x00, 0x00, 0x10 }; // blue
+        blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
+        esp_restart();  // restart, to boot OTA1 partition
+      } else {
+        uint8_t pixel[3] = { 0x00, 0x10, 0x00 }; // red
+        blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
+        ESP_LOGE("OTA", "Error setting OTA1 partition: %s", esp_err_to_name(err));
       }
-      // Abort after releasing the button
-      break;
     }
+  } else {
+    uint8_t pixel[3] = { 0x10, 0x00, 0x00 }; // green
+    blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
   }
 }
 }

From cf0a58908de30271845b036c17ef42ed2436d466 Mon Sep 17 00:00:00 2001
From: Paula Scharf <paulascharf@gmx.de>
Date: Fri, 18 Jul 2025 13:47:24 +0200
Subject: [PATCH 07/34] feat(board): remove APOTA

---
 boards.txt                        |   2 +-
 variants/sensebox_eye/APOTA.bin   | Bin 976464 -> 0 bytes
 variants/sensebox_eye/APOTA.ino   | 287 ------------------------------
 variants/sensebox_eye/variant.cpp |  54 +-----
 4 files changed, 3 insertions(+), 340 deletions(-)
 delete mode 100644 variants/sensebox_eye/APOTA.bin
 delete mode 100644 variants/sensebox_eye/APOTA.ino

diff --git a/boards.txt b/boards.txt
index faa7f94a994..2363fe2a63b 100644
--- a/boards.txt
+++ b/boards.txt
@@ -41448,7 +41448,7 @@ sensebox_eye.menu.PartitionScheme.tinyuf2=TinyUF2 Compatibility (2MB APP/12MB FF
 sensebox_eye.menu.PartitionScheme.tinyuf2.build.custom_bootloader=bootloader_tinyuf2
 sensebox_eye.menu.PartitionScheme.tinyuf2.build.custom_partitions=partitions_tinyuf2
 sensebox_eye.menu.PartitionScheme.tinyuf2.upload.maximum_size=2097152
-sensebox_eye.menu.PartitionScheme.tinyuf2.upload.extra_flags=0x410000 "{runtime.platform.path}/variants/{build.variant}/tinyuf2.bin" 0x210000 "{runtime.platform.path}/variants/{build.variant}/APOTA.bin"
+sensebox_eye.menu.PartitionScheme.tinyuf2.upload.extra_flags=0x410000 "{runtime.platform.path}/variants/{build.variant}/tinyuf2.bin"
 sensebox_eye.menu.PartitionScheme.gen4esp32scheme4=Huge App (16MB APP)
 sensebox_eye.menu.PartitionScheme.gen4esp32scheme4.build.custom_partitions=gen4esp32_16MBapp
 sensebox_eye.menu.PartitionScheme.gen4esp32scheme4.upload.maximum_size=16646144
diff --git a/variants/sensebox_eye/APOTA.bin b/variants/sensebox_eye/APOTA.bin
deleted file mode 100644
index 571336d378a9aaee97e074142d0e73cad85eacc9..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/variants/sensebox_eye/APOTA.ino b/variants/sensebox_eye/APOTA.ino
deleted file mode 100644
index afb741499b2..00000000000
--- a/variants/sensebox_eye/APOTA.ino
+++ /dev/null
@@ -1,287 +0,0 @@
-// APOTA is a arduino fallback sketch that is written to OTA1_Partition. 
-// APOTA opens an access point which waits to receive a .binfile on /sketch. 
-// After succesful upload, the file is written to OTA0_Partition and the microcontroller reboots to the newly uploaded sketch.
-
-#define DISPLAY_ENABLED
-
-#include <WiFi.h>
-#include <WebServer.h>
-#include <ESPmDNS.h>
-#include <WiFiAP.h>
-#include <Update.h>
-#include <Wire.h>
-#ifdef DISPLAY_ENABLED
-#define SCREEN_WIDTH  128
-#define SCREEN_HEIGHT 64
-#define OLED_RESET    -1
-#include <Adafruit_GFX.h>
-#include <Adafruit_SSD1306.h>
-Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
-#include <Adafruit_NeoPixel.h>
-Adafruit_NeoPixel rgb_led_1 = Adafruit_NeoPixel(1, 1, NEO_GRB + NEO_KHZ800);
-
-#endif
-#include "esp_partition.h"
-#include "esp_ota_ops.h"
-#include "esp_system.h"
-
-String ssid;
-uint8_t mac[6];
-
-// Create an instance of the server
-WebServer server(80);
-bool displayEnabled;
-
-const int BUTTON_PIN = 0;                       // GPIO for the button
-volatile unsigned long lastPressTime = 0;       // Time of last button press
-volatile bool doublePressDetected = false;      // Flag for double press
-const unsigned long doublePressInterval = 500;  // Max. time (in ms) between two presses for double press
-volatile int pressCount = 0;                    // Counts the button presses
-
-const unsigned char epd_bitmap_wifi[] PROGMEM = {
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0xff, 0x00, 0x00,
-  0x00, 0x3f, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x7c, 0x00, 0x03, 0xe0, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xf0, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x78, 0x00,
-  0x03, 0xc0, 0x00, 0x00, 0x38, 0x00, 0x07, 0x80, 0x00, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x7f, 0xe0, 0x0e, 0x00,
-  0x0c, 0x01, 0xff, 0xf0, 0x06, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x02, 0x00, 0x00, 0x0f, 0x80, 0x3e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00,
-  0x00, 0x1c, 0x00, 0x07, 0x80, 0x00, 0x00, 0x38, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x70, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x70, 0x00, 0x00, 0xc0, 0x00,
-  0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00,
-  0x00, 0x01, 0xe0, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x78, 0x00, 0x00, 0x00, 0x03, 0x80, 0x38, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-// 'checkmark', 44x44px
-const unsigned char epd_bitmap_checkmark[] PROGMEM = {
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xf0, 0x00, 0x00,
-  0x00, 0x0f, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x0f, 0x83, 0xc0, 0x00, 0x00, 0x00, 0x07, 0xc7, 0x80, 0x00, 0x00, 0x00, 0x03, 0xef, 0x00, 0x00, 0x00,
-  0x00, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-void IRAM_ATTR handleButtonPress() {
-  unsigned long currentTime = millis();  // Get current time
-
-  // Debounce: If the current press is too close to the last one, ignore it
-  if (currentTime - lastPressTime > 50) {
-    pressCount++;  // Count the button press
-
-    // Check if this is the second press within the double-press interval
-    if (pressCount == 2 && (currentTime - lastPressTime <= doublePressInterval)) {
-      doublePressDetected = true;  // Double press detected
-      pressCount = 0;              // Reset counter
-    }
-
-    lastPressTime = currentTime;  // Update the time of the last press
-  }
-}
-
-// Function to switch the boot partition to OTA1
-void setBootPartitionToOTA0() {
-  const esp_partition_t *ota0_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL);
-
-  if (ota0_partition) {
-    // Set OTA1 as new boot partition
-    esp_ota_set_boot_partition(ota0_partition);
-    Serial.println("Boot partition changed to OTA0. Restarting...");
-
-    // Restart to boot from the new partition
-    esp_restart();
-  } else {
-    Serial.println("OTA1 partition not found!");
-  }
-}
-
-void setupDisplay() {
-  displayEnabled = display.begin(SSD1306_SWITCHCAPVCC, 0x3D);
-  if (displayEnabled) {
-    display.display();
-    delay(100);
-    display.clearDisplay();
-  }
-}
-
-void displayStatusBar(int progress) {
-  display.clearDisplay();
-  display.setCursor(24, 8);
-  display.println("Sketch wird");
-  display.setCursor(22, 22);
-  display.println("hochgeladen!");
-
-  display.fillRect(0, SCREEN_HEIGHT - 24, SCREEN_WIDTH - 4, 8, BLACK);  // Clear status bar area
-  display.drawRect(0, SCREEN_HEIGHT - 24, SCREEN_WIDTH - 4, 8, WHITE);  // Draw border
-  int filledWidth = (progress * SCREEN_WIDTH - 4) / 100;                // Calculate progress width
-  display.fillRect(1, SCREEN_HEIGHT - 23, filledWidth - 4, 6, WHITE);   // Fill progress bar
-
-  display.setCursor((SCREEN_WIDTH / 2) - 12, SCREEN_HEIGHT - 10);
-  display.setTextSize(1);
-  display.setTextColor(WHITE, BLACK);
-  display.print(progress);
-  display.println(" %");
-  display.display();
-}
-
-void displayWelcomeScreen() {
-  display.clearDisplay();
-
-  // Draw WiFi symbol
-  display.drawBitmap(0, 12, epd_bitmap_wifi, 44, 44, WHITE);
-
-  // Display SSID text
-  display.setCursor(40, 13);
-  display.setTextSize(1);
-  display.setTextColor(WHITE, BLACK);
-  display.println("Verbinde dich");  // "Connect"
-  display.setCursor(60, 27);
-  display.println("mit:");  // "with"
-
-  // Display SSID
-  display.setCursor(40, 43);
-  display.setTextSize(1);  // Larger text for SSID
-  display.print(ssid);
-
-  display.display();
-}
-
-void displaySuccessScreen() {
-  display.clearDisplay();
-
-  // Draw WiFi symbol
-  display.drawBitmap(0, 12, epd_bitmap_checkmark, 44, 44, WHITE);
-
-  // Display SSID text
-  display.setCursor(48, 22);
-  display.setTextSize(1);
-  display.setTextColor(WHITE, BLACK);
-  display.println("Erfolgreich");  // "Successfully"
-  display.setCursor(48, 36);
-  display.println("hochgeladen!");  // "uploaded!"
-
-  display.display();
-}
-
-void wipeDisplay() {
-  display.clearDisplay();
-  display.println("");
-  display.display();
-}
-
-void setupWiFi() {
-  WiFi.macAddress(mac);
-  char macLastFour[5];
-  snprintf(macLastFour, sizeof(macLastFour), "%02X%02X", mac[4], mac[5]);
-  ssid = "senseBox:" + String(macLastFour);
-
-  // Define the IP address, gateway, and subnet mask
-  IPAddress local_IP(192, 168, 1, 1);  // The new IP address
-  IPAddress gateway(192, 168, 1, 1);   // Gateway address (can be the same as the AP's IP)
-  IPAddress subnet(255, 255, 255, 0);  // Subnet mask
-
-  // Set the IP address, gateway, and subnet mask of the access point
-  WiFi.softAPConfig(local_IP, gateway, subnet);
-
-  // Start the access point
-  WiFi.softAP(ssid.c_str());
-}
-
-void setupOTA() {
-  // Handle updating process
-  server.on(
-    "/sketch", HTTP_POST,
-    []() {
-      server.sendHeader("Connection", "close");
-      server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
-      ESP.restart();
-    },
-    []() {
-      HTTPUpload &upload = server.upload();
-
-      if (upload.status == UPLOAD_FILE_START) {
-        Serial.setDebugOutput(true);
-        size_t fsize = UPDATE_SIZE_UNKNOWN;
-        if (server.clientContentLength() > 0) {
-          fsize = server.clientContentLength();
-        }
-        Serial.printf("Receiving Update: %s, Size: %d\n", upload.filename.c_str(), fsize);
-
-        Serial.printf("Update: %s\n", upload.filename.c_str());
-        if (!Update.begin(fsize)) {  //start with max available size
-          Update.printError(Serial);
-        }
-      } else if (upload.status == UPLOAD_FILE_WRITE) {
-        /* flashing firmware to ESP*/
-        if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
-          Update.printError(Serial);
-        } else {
-          int progress = (Update.progress() * 100) / Update.size();
-          displayStatusBar(progress);  // Update progress on status bar
-        }
-      } else if (upload.status == UPLOAD_FILE_END) {
-        if (Update.end(true)) {  //true to set the size to the current progress
-          displaySuccessScreen();
-          delay(3000);
-          wipeDisplay();
-        } else {
-          Update.printError(Serial);
-        }
-        Serial.setDebugOutput(false);
-      }
-      yield();
-    }
-  );
-}
-
-void setup() {
-  // Start Serial communication
-  Serial.begin(115200);
-  rgb_led_1.begin();
-  rgb_led_1.setBrightness(30);
-  rgb_led_1.setPixelColor(0, rgb_led_1.Color(51, 51, 255));
-  rgb_led_1.show();
-
-  // Configure button pin as input
-  pinMode(BUTTON_PIN, INPUT_PULLUP);
-
-  // Interrupt for the button
-  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), handleButtonPress, FALLING);
-
-#ifdef DISPLAY_ENABLED
-  setupDisplay();
-#endif
-  setupWiFi();
-  // Set the ESP32 as an access point
-  setupOTA();
-  server.begin();
-}
-
-void loop() {
-  // Handle client requests
-  server.handleClient();
-
-#ifdef DISPLAY_ENABLED
-  displayWelcomeScreen();
-#endif
-
-  if (doublePressDetected) {
-    Serial.println("Doppeldruck erkannt!");  // "Double press detected!"
-    setBootPartitionToOTA0();
-#ifdef DISPLAY_ENABLED
-    display.setCursor(0, 0);
-    display.setTextSize(1);
-    display.setTextColor(WHITE, BLACK);
-    display.println("");
-    display.display();
-    delay(50);
-#endif
-    // Restart to boot from the new partition
-    esp_restart();
-  }
-}
diff --git a/variants/sensebox_eye/variant.cpp b/variants/sensebox_eye/variant.cpp
index 1eef839494e..d8a37f58758 100644
--- a/variants/sensebox_eye/variant.cpp
+++ b/variants/sensebox_eye/variant.cpp
@@ -1,34 +1,6 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2021 Ha Thach (tinyusb.org) for Adafruit Industries
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
 #include "esp32-hal-gpio.h"
 #include "pins_arduino.h"
 #include "driver/rmt_tx.h"
-#include "esp_log.h"
-#include "esp_partition.h"
-#include "esp_system.h"
-#include "esp_ota_ops.h"
 
 extern "C" {
 
@@ -72,29 +44,7 @@ void initVariant(void) {
     .loop_count = 0
   };
 
-  // define button pin
-  pinMode(47, INPUT_PULLUP);
-
-  // Check if button is pressed
-  if (digitalRead(47) == LOW) {
-    // When the button is pressed and then released, boot into the OTA1 partition
-    const esp_partition_t *ota1_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL);
-
-    if (ota1_partition) {
-      esp_err_t err = esp_ota_set_boot_partition(ota1_partition);
-      if (err == ESP_OK) {
-        uint8_t pixel[3] = { 0x00, 0x00, 0x10 }; // blue
-        blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
-        esp_restart();  // restart, to boot OTA1 partition
-      } else {
-        uint8_t pixel[3] = { 0x00, 0x10, 0x00 }; // red
-        blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
-        ESP_LOGE("OTA", "Error setting OTA1 partition: %s", esp_err_to_name(err));
-      }
-    }
-  } else {
-    uint8_t pixel[3] = { 0x10, 0x00, 0x00 }; // green
-    blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
-  }
+  uint8_t pixel[3] = { 0x10, 0x00, 0x00 }; // green
+  blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
 }
 }

From 28e90766018ffe46fef16526487ba2a905052e53 Mon Sep 17 00:00:00 2001
From: Paula Scharf <paulascharf@gmx.de>
Date: Sun, 20 Jul 2025 22:53:35 +0200
Subject: [PATCH 08/34] feat(board): build name uppercase

---
 boards.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/boards.txt b/boards.txt
index 2363fe2a63b..07c34649ea0 100644
--- a/boards.txt
+++ b/boards.txt
@@ -41343,7 +41343,7 @@ sensebox_eye.build.target=esp32s3
 sensebox_eye.build.mcu=esp32s3
 sensebox_eye.build.core=esp32
 sensebox_eye.build.variant=sensebox_eye
-sensebox_eye.build.board=sensebox_eye
+sensebox_eye.build.board=SENSEBOX_EYE
 
 sensebox_eye.build.usb_mode=0
 sensebox_eye.build.cdc_on_boot=1

From 349b11d2d86b37f3e6613cf25ea490b02c9fdecf Mon Sep 17 00:00:00 2001
From: Paula Scharf <paulascharf@gmx.de>
Date: Sun, 20 Jul 2025 23:00:05 +0200
Subject: [PATCH 09/34] feat(board): name tag lowercase

---
 boards.txt | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/boards.txt b/boards.txt
index 07c34649ea0..1043ece4445 100644
--- a/boards.txt
+++ b/boards.txt
@@ -41313,12 +41313,12 @@ sensebox_mcu_esp32s2.menu.EraseFlash.all.upload.erase_cmd=-e
 # senseBox Eye
 
 sensebox_eye.name=senseBox Eye
-senseBox_eye.vid.0=0x303A
-senseBox_eye.pid.0=0x82D1
-senseBox_eye.vid.1=0x303A
-senseBox_eye.pid.1=0x82D2
-senseBox_eye.vid.2=0x303A
-senseBox_eye.pid.2=0x82D3
+sensebox_eye.vid.0=0x303A
+sensebox_eye.pid.0=0x82D1
+sensebox_eye.vid.1=0x303A
+sensebox_eye.pid.1=0x82D2
+sensebox_eye.vid.2=0x303A
+sensebox_eye.pid.2=0x82D3
 
 sensebox_eye.bootloader.tool=esptool_py
 sensebox_eye.bootloader.tool.default=esptool_py

From e92e631811002adba98eb1e8e0ce167755e0864f Mon Sep 17 00:00:00 2001
From: Angel Nunez Mencias <git@angelnu.com>
Date: Wed, 23 Jul 2025 07:11:11 +0200
Subject: [PATCH 10/34] feat: Allow calls to timer functions within ISR

---
 cores/esp32/esp32-hal-timer.c | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/cores/esp32/esp32-hal-timer.c b/cores/esp32/esp32-hal-timer.c
index ec6c507358e..508d510508e 100644
--- a/cores/esp32/esp32-hal-timer.c
+++ b/cores/esp32/esp32-hal-timer.c
@@ -36,9 +36,8 @@ struct timer_struct_t {
   bool timer_started;
 };
 
-inline uint64_t timerRead(hw_timer_t *timer) {
+inline IRAM_ATTR uint64_t timerRead(hw_timer_t *timer) {
   if (timer == NULL) {
-    log_e("Timer handle is NULL");
     return 0;
   }
   uint64_t value;
@@ -46,15 +45,14 @@ inline uint64_t timerRead(hw_timer_t *timer) {
   return value;
 }
 
-void timerWrite(hw_timer_t *timer, uint64_t val) {
+void IRAM_ATTR timerWrite(hw_timer_t *timer, uint64_t val) {
   if (timer == NULL) {
-    log_e("Timer handle is NULL");
     return;
   }
   gptimer_set_raw_count(timer->timer_handle, val);
 }
 
-void timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count) {
+void IRAM_ATTR timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count) {
   if (timer == NULL) {
     log_e("Timer handle is NULL");
     return;
@@ -67,7 +65,7 @@ void timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autoreload, uint64
   };
   err = gptimer_set_alarm_action(timer->timer_handle, &alarm_cfg);
   if (err != ESP_OK) {
-    log_e("Timer Alarm Write failed, error num=%d", err);
+    ; // Ignore
   }
 }
 
@@ -80,27 +78,24 @@ uint32_t timerGetFrequency(hw_timer_t *timer) {
   return frequency;
 }
 
-void timerStart(hw_timer_t *timer) {
+void IRAM_ATTR timerStart(hw_timer_t *timer) {
   if (timer == NULL) {
-    log_e("Timer handle is NULL");
     return;
   }
   gptimer_start(timer->timer_handle);
   timer->timer_started = true;
 }
 
-void timerStop(hw_timer_t *timer) {
+void IRAM_ATTR timerStop(hw_timer_t *timer) {
   if (timer == NULL) {
-    log_e("Timer handle is NULL");
     return;
   }
   gptimer_stop(timer->timer_handle);
   timer->timer_started = false;
 }
 
-void timerRestart(hw_timer_t *timer) {
+void IRAM_ATTR timerRestart(hw_timer_t *timer) {
   if (timer == NULL) {
-    log_e("Timer handle is NULL");
     return;
   }
   gptimer_set_raw_count(timer->timer_handle, 0);

From 67c59a202196abe0029b868c34e57faf4032f0c5 Mon Sep 17 00:00:00 2001
From: Angel Nunez Mencias <git@angelnu.com>
Date: Wed, 23 Jul 2025 07:26:03 +0200
Subject: [PATCH 11/34] fix: remove log from IRAM function

---
 cores/esp32/esp32-hal-timer.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/cores/esp32/esp32-hal-timer.c b/cores/esp32/esp32-hal-timer.c
index 508d510508e..6875b5b2d8f 100644
--- a/cores/esp32/esp32-hal-timer.c
+++ b/cores/esp32/esp32-hal-timer.c
@@ -54,7 +54,6 @@ void IRAM_ATTR timerWrite(hw_timer_t *timer, uint64_t val) {
 
 void IRAM_ATTR timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count) {
   if (timer == NULL) {
-    log_e("Timer handle is NULL");
     return;
   }
   esp_err_t err = ESP_OK;

From c7520ccef0c343611d7f9eb0afb3576f612de2f2 Mon Sep 17 00:00:00 2001
From: Me No Dev <me-no-dev@users.noreply.github.com>
Date: Wed, 23 Jul 2025 17:15:59 +0300
Subject: [PATCH 12/34] fix(report): Update Issue-report.yml for version 3.3.0

---
 .github/ISSUE_TEMPLATE/Issue-report.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/ISSUE_TEMPLATE/Issue-report.yml b/.github/ISSUE_TEMPLATE/Issue-report.yml
index 6dc1b0de171..a16a6ae3d44 100644
--- a/.github/ISSUE_TEMPLATE/Issue-report.yml
+++ b/.github/ISSUE_TEMPLATE/Issue-report.yml
@@ -43,6 +43,7 @@ body:
         - latest stable Release (if not listed below)
         - latest development Release Candidate (RC-X)
         - latest master (checkout manually)
+        - v3.3.0
         - v3.2.1
         - v3.2.0
         - v3.1.3

From 126039663f83b3d6f5868a30f7dc2093812ee7b4 Mon Sep 17 00:00:00 2001
From: Angel Nunez Mencias <git@angelnu.com>
Date: Thu, 24 Jul 2025 00:09:17 +0200
Subject: [PATCH 13/34] fix: conditional logs when not ISR

---
 cores/esp32/esp32-hal-timer.c | 40 +++++++++++++++++++++++++++++------
 1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/cores/esp32/esp32-hal-timer.c b/cores/esp32/esp32-hal-timer.c
index 6875b5b2d8f..38575fc9799 100644
--- a/cores/esp32/esp32-hal-timer.c
+++ b/cores/esp32/esp32-hal-timer.c
@@ -22,6 +22,12 @@
 #include "esp_clk_tree.h"
 #endif
 
+#if CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+#define TIMER_IRAM IRAM_ATTR
+#else
+#define TIMER_IRAM
+#endif
+
 typedef void (*voidFuncPtr)(void);
 typedef void (*voidFuncPtrArg)(void *);
 
@@ -36,8 +42,11 @@ struct timer_struct_t {
   bool timer_started;
 };
 
-inline IRAM_ATTR uint64_t timerRead(hw_timer_t *timer) {
+inline TIMER_IRAM uint64_t timerRead(hw_timer_t *timer) {
   if (timer == NULL) {
+    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+    log_e("Timer handle is NULL");
+    #endif
     return 0;
   }
   uint64_t value;
@@ -45,15 +54,21 @@ inline IRAM_ATTR uint64_t timerRead(hw_timer_t *timer) {
   return value;
 }
 
-void IRAM_ATTR timerWrite(hw_timer_t *timer, uint64_t val) {
+void TIMER_IRAM timerWrite(hw_timer_t *timer, uint64_t val) {
   if (timer == NULL) {
+    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+    log_e("Timer handle is NULL");
+    #endif
     return;
   }
   gptimer_set_raw_count(timer->timer_handle, val);
 }
 
-void IRAM_ATTR timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count) {
+void TIMER_IRAM timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count) {
   if (timer == NULL) {
+    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+    log_e("Timer handle is NULL");
+    #endif
     return;
   }
   esp_err_t err = ESP_OK;
@@ -64,7 +79,9 @@ void IRAM_ATTR timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autorelo
   };
   err = gptimer_set_alarm_action(timer->timer_handle, &alarm_cfg);
   if (err != ESP_OK) {
-    ; // Ignore
+    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+    log_e("Timer Alarm Write failed, error num=%d", err);
+    #endif
   }
 }
 
@@ -77,24 +94,33 @@ uint32_t timerGetFrequency(hw_timer_t *timer) {
   return frequency;
 }
 
-void IRAM_ATTR timerStart(hw_timer_t *timer) {
+void TIMER_IRAM timerStart(hw_timer_t *timer) {
   if (timer == NULL) {
+    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+    log_e("Timer handle is NULL");
+    #endif
     return;
   }
   gptimer_start(timer->timer_handle);
   timer->timer_started = true;
 }
 
-void IRAM_ATTR timerStop(hw_timer_t *timer) {
+void TIMER_IRAM timerStop(hw_timer_t *timer) {
   if (timer == NULL) {
+    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+    log_e("Timer handle is NULL");
+    #endif
     return;
   }
   gptimer_stop(timer->timer_handle);
   timer->timer_started = false;
 }
 
-void IRAM_ATTR timerRestart(hw_timer_t *timer) {
+void TIMER_IRAM timerRestart(hw_timer_t *timer) {
   if (timer == NULL) {
+    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+    log_e("Timer handle is NULL");
+    #endif
     return;
   }
   gptimer_set_raw_count(timer->timer_handle, 0);

From e3a0a3a6c58eca709dacf6f1d2e7cd169f522e86 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci-lite[bot]"
 <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Date: Thu, 24 Jul 2025 11:22:13 +0000
Subject: [PATCH 14/34] ci(pre-commit): Apply automatic fixes

---
 cores/esp32/esp32-hal-timer.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/cores/esp32/esp32-hal-timer.c b/cores/esp32/esp32-hal-timer.c
index 38575fc9799..85e007143bd 100644
--- a/cores/esp32/esp32-hal-timer.c
+++ b/cores/esp32/esp32-hal-timer.c
@@ -44,9 +44,9 @@ struct timer_struct_t {
 
 inline TIMER_IRAM uint64_t timerRead(hw_timer_t *timer) {
   if (timer == NULL) {
-    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+#ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
     log_e("Timer handle is NULL");
-    #endif
+#endif
     return 0;
   }
   uint64_t value;
@@ -56,9 +56,9 @@ inline TIMER_IRAM uint64_t timerRead(hw_timer_t *timer) {
 
 void TIMER_IRAM timerWrite(hw_timer_t *timer, uint64_t val) {
   if (timer == NULL) {
-    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+#ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
     log_e("Timer handle is NULL");
-    #endif
+#endif
     return;
   }
   gptimer_set_raw_count(timer->timer_handle, val);
@@ -66,9 +66,9 @@ void TIMER_IRAM timerWrite(hw_timer_t *timer, uint64_t val) {
 
 void TIMER_IRAM timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count) {
   if (timer == NULL) {
-    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+#ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
     log_e("Timer handle is NULL");
-    #endif
+#endif
     return;
   }
   esp_err_t err = ESP_OK;
@@ -79,9 +79,9 @@ void TIMER_IRAM timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autorel
   };
   err = gptimer_set_alarm_action(timer->timer_handle, &alarm_cfg);
   if (err != ESP_OK) {
-    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+#ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
     log_e("Timer Alarm Write failed, error num=%d", err);
-    #endif
+#endif
   }
 }
 
@@ -96,9 +96,9 @@ uint32_t timerGetFrequency(hw_timer_t *timer) {
 
 void TIMER_IRAM timerStart(hw_timer_t *timer) {
   if (timer == NULL) {
-    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+#ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
     log_e("Timer handle is NULL");
-    #endif
+#endif
     return;
   }
   gptimer_start(timer->timer_handle);
@@ -107,9 +107,9 @@ void TIMER_IRAM timerStart(hw_timer_t *timer) {
 
 void TIMER_IRAM timerStop(hw_timer_t *timer) {
   if (timer == NULL) {
-    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+#ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
     log_e("Timer handle is NULL");
-    #endif
+#endif
     return;
   }
   gptimer_stop(timer->timer_handle);
@@ -118,9 +118,9 @@ void TIMER_IRAM timerStop(hw_timer_t *timer) {
 
 void TIMER_IRAM timerRestart(hw_timer_t *timer) {
   if (timer == NULL) {
-    #ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
+#ifndef CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
     log_e("Timer handle is NULL");
-    #endif
+#endif
     return;
   }
   gptimer_set_raw_count(timer->timer_handle, 0);

From 5c24611b913e90d65d75b5208359f6364a2509f9 Mon Sep 17 00:00:00 2001
From: Parsaabasi <mohammadabbasi970@gmail.com>
Date: Fri, 25 Jul 2025 12:35:55 +0200
Subject: [PATCH 15/34] feat(github): remove ESP32 forum from issue template

---
 .github/ISSUE_TEMPLATE/config.yml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index e879b09bec2..060397abd1e 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -3,6 +3,3 @@ contact_links:
   - name: Arduino Core for Espressif Discord Server
     url: https://discord.gg/8xY6e9crwv
     about: Community Discord server for questions and help
-  - name: ESP32 Forum - Arduino
-    url: https://esp32.com/viewforum.php?f=19
-    about: Official Forum for questions

From 10e73be7146d6b6d80777016bdc4ddb810cf56a7 Mon Sep 17 00:00:00 2001
From: Parsaabasi <mohammadabbasi970@gmail.com>
Date: Fri, 25 Jul 2025 12:49:46 +0200
Subject: [PATCH 16/34] feat(github): Update template type

---
 .github/ISSUE_TEMPLATE/Issue-report.yml | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/.github/ISSUE_TEMPLATE/Issue-report.yml b/.github/ISSUE_TEMPLATE/Issue-report.yml
index a16a6ae3d44..864ef65b92b 100644
--- a/.github/ISSUE_TEMPLATE/Issue-report.yml
+++ b/.github/ISSUE_TEMPLATE/Issue-report.yml
@@ -80,6 +80,17 @@ body:
         - other
     validations:
       required: true
+ - type: dropdown
+    id: type
+    attributes:
+      label: Type
+      description: How would you define the type of the issue? Please select from the types below.
+      options:
+        - Task
+        - Bug
+        - Question
+    validations:
+      required: true
   - type: input
     id: IDE
     attributes:

From b3152a4ffc38f374cb70ff999f3c64a9bef75297 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Proch=C3=A1zka?=
 <90197375+P-R-O-C-H-Y@users.noreply.github.com>
Date: Fri, 25 Jul 2025 14:10:32 +0200
Subject: [PATCH 17/34] feat(zigbee): Update SDK to latest

---
 idf_component.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/idf_component.yml b/idf_component.yml
index 82f14ea554a..f9357a401f9 100644
--- a/idf_component.yml
+++ b/idf_component.yml
@@ -54,12 +54,12 @@ dependencies:
   espressif/esp_modem:
     version: "^1.1.0"
   espressif/esp-zboss-lib:
-    version: "==1.6.4" # compatible with esp-zigbee-lib 1.6.5
+    version: "==1.6.4" # compatible with esp-zigbee-lib 1.6.6
     require: public
     rules:
       - if: "target not in [esp32c2, esp32p4]"
   espressif/esp-zigbee-lib:
-    version: "==1.6.5"
+    version: "==1.6.6"
     require: public
     rules:
       - if: "target not in [esp32c2, esp32p4]"

From b139bae5028ac2be25cd91943f62c7546b307ea1 Mon Sep 17 00:00:00 2001
From: Wulu <wulu@wulu.zone>
Date: Sun, 27 Jul 2025 19:50:20 +0800
Subject: [PATCH 18/34] docs: Remove incorrect statement on ESP32-S3 default
 resolution

---
 docs/en/api/adc.rst | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/docs/en/api/adc.rst b/docs/en/api/adc.rst
index 434384f8d9b..9c16db54ec1 100644
--- a/docs/en/api/adc.rst
+++ b/docs/en/api/adc.rst
@@ -52,8 +52,7 @@ This function will return analog value in millivolts (calibrated).
 analogReadResolution
 ^^^^^^^^^^^^^^^^^^^^
 
-This function is used to set the resolution of ``analogRead`` return value. Default is 12 bits (range from 0 to 4095)
-for all chips except ESP32-S3 where default is 13 bits (range from 0 to 8191).
+This function is used to set the resolution of ``analogRead`` return value. Default is 12 bits (range from 0 to 4095).
 When different resolution is set, the values read will be shifted to match the given resolution.
 
 Range is 1 - 16 .The default value will be used, if this function is not used.

From ed6e95d4fc207575d932dc12a7783eff724280f4 Mon Sep 17 00:00:00 2001
From: Paula Scharf <paulascharf@gmx.de>
Date: Mon, 28 Jul 2025 08:46:14 +0200
Subject: [PATCH 19/34] feat(board): use existing led API

---
 variants/sensebox_eye/variant.cpp | 46 +++----------------------------
 1 file changed, 4 insertions(+), 42 deletions(-)

diff --git a/variants/sensebox_eye/variant.cpp b/variants/sensebox_eye/variant.cpp
index d8a37f58758..23bc1d385f7 100644
--- a/variants/sensebox_eye/variant.cpp
+++ b/variants/sensebox_eye/variant.cpp
@@ -1,50 +1,12 @@
 #include "esp32-hal-gpio.h"
 #include "pins_arduino.h"
-#include "driver/rmt_tx.h"
 
 extern "C" {
 
-void blinkLED(uint8_t color[3], rmt_channel_handle_t led_chan, rmt_encoder_handle_t ws2812_encoder, rmt_transmit_config_t tx_config) {
-  ESP_ERROR_CHECK(rmt_transmit(led_chan, ws2812_encoder, color, sizeof(color), &tx_config));
-  rmt_tx_wait_all_done(led_chan, portMAX_DELAY);
-
-  // Wait a moment
-  delay(50);
-
-  // Turn LED off
-  uint8_t pixel_off[3] = { 0x00, 0x00, 0x00 };
-  ESP_ERROR_CHECK(rmt_transmit(led_chan, ws2812_encoder, pixel_off, sizeof(pixel_off), &tx_config));
-  rmt_tx_wait_all_done(led_chan, portMAX_DELAY);
-}
-
 void initVariant(void) {
-  rmt_channel_handle_t led_chan = NULL;
-  rmt_tx_channel_config_t tx_chan_config = {};
-  tx_chan_config.clk_src = RMT_CLK_SRC_DEFAULT;
-  tx_chan_config.resolution_hz = 10 * 1000 * 1000;
-  tx_chan_config.mem_block_symbols = 64;
-  tx_chan_config.trans_queue_depth = 4;
-  tx_chan_config.gpio_num = (gpio_num_t)PIN_LED;
-  tx_chan_config.flags.invert_out = false;
-  tx_chan_config.flags.with_dma = false;
-  ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan));
-
-  // WS2812 encoder config (available in `esp-rmt`)
-  rmt_encoder_handle_t ws2812_encoder = NULL;
-  rmt_bytes_encoder_config_t bytes_encoder_config = {
-    .bit0 = { .duration0 = 4, .level0 = 1, .duration1 = 9, .level1 = 0 },
-    .bit1 = { .duration0 = 8, .level0 = 1, .duration1 = 5, .level1 = 0 },
-    .flags = { .msb_first = true }
-  };
-  ESP_ERROR_CHECK(rmt_new_bytes_encoder(&bytes_encoder_config, &ws2812_encoder));
-
-  ESP_ERROR_CHECK(rmt_enable(led_chan));
-
-  rmt_transmit_config_t tx_config = {
-    .loop_count = 0
-  };
-
-  uint8_t pixel[3] = { 0x10, 0x00, 0x00 }; // green
-  blinkLED(pixel, led_chan, ws2812_encoder, tx_config);
+  // blink the RGB LED
+  rgbLedWrite(PIN_LED, 0x00, 0x10, 0x00); // green
+  delay(20);
+  rgbLedWrite(PIN_LED, 0x00, 0x00, 0x00); // off
 }
 }

From 0dcb1d1178c0d8c73870a83f892fada1114d8fc0 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci-lite[bot]"
 <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Date: Mon, 28 Jul 2025 06:56:12 +0000
Subject: [PATCH 20/34] ci(pre-commit): Apply automatic fixes

---
 .../sensebox_eye/partitions-16MB-tinyuf2.csv  |  2 +-
 variants/sensebox_eye/pins_arduino.h          | 26 +++++++++----------
 variants/sensebox_eye/variant.cpp             |  4 +--
 variants/sensebox_mcu_esp32s2/APOTA.ino       |  4 +--
 4 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/variants/sensebox_eye/partitions-16MB-tinyuf2.csv b/variants/sensebox_eye/partitions-16MB-tinyuf2.csv
index 960f3fbbd71..55dc6213161 100644
--- a/variants/sensebox_eye/partitions-16MB-tinyuf2.csv
+++ b/variants/sensebox_eye/partitions-16MB-tinyuf2.csv
@@ -7,4 +7,4 @@ otadata,  data, ota,      0xe000,  8K,
 ota_0,    0,    ota_0,   0x10000,  2048K,
 ota_1,    0,    ota_1,  0x210000,  2048K,
 uf2,      app,  factory,0x410000,  256K,
-ffat,     data, fat,    0x450000,  11968K,
\ No newline at end of file
+ffat,     data, fat,    0x450000,  11968K,
diff --git a/variants/sensebox_eye/pins_arduino.h b/variants/sensebox_eye/pins_arduino.h
index 99984dbc6a4..70c2bd880c9 100644
--- a/variants/sensebox_eye/pins_arduino.h
+++ b/variants/sensebox_eye/pins_arduino.h
@@ -10,15 +10,15 @@
 #define USB_SERIAL       ""  // Empty string for MAC address
 
 // Default USB FirmwareMSC Settings
-#define USB_FW_MSC_VENDOR_ID        "senseBox"        // max 8 chars
+#define USB_FW_MSC_VENDOR_ID        "senseBox"     // max 8 chars
 #define USB_FW_MSC_PRODUCT_ID       "Eye ESP32S3"  // max 16 chars
-#define USB_FW_MSC_PRODUCT_REVISION "1.00"            // max 4 chars
-#define USB_FW_MSC_VOLUME_NAME      "senseBox"        // max 11 chars
+#define USB_FW_MSC_PRODUCT_REVISION "1.00"         // max 4 chars
+#define USB_FW_MSC_VOLUME_NAME      "senseBox"     // max 11 chars
 #define USB_FW_MSC_SERIAL_NUMBER    0x00000000
 
 #define PIN_RGB_LED 45  // RGB LED
 #define RGBLED_PIN  45  // RGB LED
-#define PIN_LED   45
+#define PIN_LED     45
 #define RGBLED_NUM  1  // number of RGB LEDs
 
 // Default I2C QWIIC-Ports
@@ -28,14 +28,14 @@ static const uint8_t SCL = 1;
 #define PIN_QWIIC_SCL 1
 
 // IO Pins
-#define PIN_IO14   14
-static const uint8_t A14 = PIN_IO14; // Analog
-static const uint8_t D14 = PIN_IO14; // Digital
-static const uint8_t T14 = PIN_IO14; // Touch
-#define PIN_IO48   48
-static const uint8_t A48 = PIN_IO48; // Analog
-static const uint8_t D48 = PIN_IO48; // Digital
-static const uint8_t T48 = PIN_IO48; // Touch
+#define PIN_IO14 14
+static const uint8_t A14 = PIN_IO14;  // Analog
+static const uint8_t D14 = PIN_IO14;  // Digital
+static const uint8_t T14 = PIN_IO14;  // Touch
+#define PIN_IO48 48
+static const uint8_t A48 = PIN_IO48;  // Analog
+static const uint8_t D48 = PIN_IO48;  // Digital
+static const uint8_t T48 = PIN_IO48;  // Touch
 
 // Button
 #define PIN_BUTTON 47
@@ -87,4 +87,4 @@ static const uint8_t RX = 44;
 #define LORA_TX 43
 #define LORA_RX 44
 
-#endif /* Pins_Arduino_h */
\ No newline at end of file
+#endif /* Pins_Arduino_h */
diff --git a/variants/sensebox_eye/variant.cpp b/variants/sensebox_eye/variant.cpp
index 23bc1d385f7..4d6e38e73e0 100644
--- a/variants/sensebox_eye/variant.cpp
+++ b/variants/sensebox_eye/variant.cpp
@@ -5,8 +5,8 @@ extern "C" {
 
 void initVariant(void) {
   // blink the RGB LED
-  rgbLedWrite(PIN_LED, 0x00, 0x10, 0x00); // green
+  rgbLedWrite(PIN_LED, 0x00, 0x10, 0x00);  // green
   delay(20);
-  rgbLedWrite(PIN_LED, 0x00, 0x00, 0x00); // off
+  rgbLedWrite(PIN_LED, 0x00, 0x00, 0x00);  // off
 }
 }
diff --git a/variants/sensebox_mcu_esp32s2/APOTA.ino b/variants/sensebox_mcu_esp32s2/APOTA.ino
index afb741499b2..114f0325e92 100644
--- a/variants/sensebox_mcu_esp32s2/APOTA.ino
+++ b/variants/sensebox_mcu_esp32s2/APOTA.ino
@@ -1,5 +1,5 @@
-// APOTA is a arduino fallback sketch that is written to OTA1_Partition. 
-// APOTA opens an access point which waits to receive a .binfile on /sketch. 
+// APOTA is a arduino fallback sketch that is written to OTA1_Partition.
+// APOTA opens an access point which waits to receive a .binfile on /sketch.
 // After succesful upload, the file is written to OTA0_Partition and the microcontroller reboots to the newly uploaded sketch.
 
 #define DISPLAY_ENABLED

From e375698adeb0d3ef306782b1a669bf7a60d6b190 Mon Sep 17 00:00:00 2001
From: Paula Scharf <paulascharf@gmx.de>
Date: Mon, 28 Jul 2025 09:44:04 +0200
Subject: [PATCH 21/34] feat(board): spelling

---
 variants/sensebox_mcu_esp32s2/APOTA.ino | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/variants/sensebox_mcu_esp32s2/APOTA.ino b/variants/sensebox_mcu_esp32s2/APOTA.ino
index 114f0325e92..a1fbab402ca 100644
--- a/variants/sensebox_mcu_esp32s2/APOTA.ino
+++ b/variants/sensebox_mcu_esp32s2/APOTA.ino
@@ -1,6 +1,6 @@
-// APOTA is a arduino fallback sketch that is written to OTA1_Partition.
-// APOTA opens an access point which waits to receive a .binfile on /sketch.
-// After succesful upload, the file is written to OTA0_Partition and the microcontroller reboots to the newly uploaded sketch.
+// APOTA is an Arduino fallback sketch that is written to OTA1_Partition. 
+// APOTA opens an access point which waits to receive a .bin file on /sketch. 
+// After successful upload, the file is written to OTA0_Partition, and the microcontroller reboots to the newly uploaded sketch.
 
 #define DISPLAY_ENABLED
 

From a5e85f675e09aa9e5532dd9e4e24019e243f3ee8 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci-lite[bot]"
 <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Date: Mon, 28 Jul 2025 07:44:47 +0000
Subject: [PATCH 22/34] ci(pre-commit): Apply automatic fixes

---
 variants/sensebox_mcu_esp32s2/APOTA.ino | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/variants/sensebox_mcu_esp32s2/APOTA.ino b/variants/sensebox_mcu_esp32s2/APOTA.ino
index a1fbab402ca..67348d0b20f 100644
--- a/variants/sensebox_mcu_esp32s2/APOTA.ino
+++ b/variants/sensebox_mcu_esp32s2/APOTA.ino
@@ -1,5 +1,5 @@
-// APOTA is an Arduino fallback sketch that is written to OTA1_Partition. 
-// APOTA opens an access point which waits to receive a .bin file on /sketch. 
+// APOTA is an Arduino fallback sketch that is written to OTA1_Partition.
+// APOTA opens an access point which waits to receive a .bin file on /sketch.
 // After successful upload, the file is written to OTA0_Partition, and the microcontroller reboots to the newly uploaded sketch.
 
 #define DISPLAY_ENABLED

From 311955ccbb0fa657ff6e03fcdd553bd5094c826a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Proch=C3=A1zka?=
 <90197375+P-R-O-C-H-Y@users.noreply.github.com>
Date: Mon, 28 Jul 2025 11:59:01 +0200
Subject: [PATCH 23/34] fix(component): Use external diag logs to avoid error

---
 idf_component_examples/esp_matter_light/sdkconfig.defaults   | 5 +++++
 idf_component_examples/hello_world/sdkconfig.defaults        | 5 +++++
 idf_component_examples/hw_cdc_hello_world/sdkconfig.defaults | 5 +++++
 3 files changed, 15 insertions(+)

diff --git a/idf_component_examples/esp_matter_light/sdkconfig.defaults b/idf_component_examples/esp_matter_light/sdkconfig.defaults
index 43871661856..8688318fa36 100644
--- a/idf_component_examples/esp_matter_light/sdkconfig.defaults
+++ b/idf_component_examples/esp_matter_light/sdkconfig.defaults
@@ -60,3 +60,8 @@ CONFIG_MBEDTLS_HKDF_C=y
 # Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1)
 # unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
 CONFIG_LWIP_IPV6_NUM_ADDRESSES=6
+
+#
+# DIAGNOSTICS
+#
+CONFIG_DIAG_USE_EXTERNAL_LOG_WRAP=y
diff --git a/idf_component_examples/hello_world/sdkconfig.defaults b/idf_component_examples/hello_world/sdkconfig.defaults
index bb723653f8a..a604d9767fd 100644
--- a/idf_component_examples/hello_world/sdkconfig.defaults
+++ b/idf_component_examples/hello_world/sdkconfig.defaults
@@ -10,3 +10,8 @@ CONFIG_AUTOSTART_ARDUINO=y
 CONFIG_FREERTOS_HZ=1000
 # end of FREERTOS
 # end of Component config
+
+#
+# DIAGNOSTICS
+#
+CONFIG_DIAG_USE_EXTERNAL_LOG_WRAP=y
diff --git a/idf_component_examples/hw_cdc_hello_world/sdkconfig.defaults b/idf_component_examples/hw_cdc_hello_world/sdkconfig.defaults
index bb723653f8a..a604d9767fd 100644
--- a/idf_component_examples/hw_cdc_hello_world/sdkconfig.defaults
+++ b/idf_component_examples/hw_cdc_hello_world/sdkconfig.defaults
@@ -10,3 +10,8 @@ CONFIG_AUTOSTART_ARDUINO=y
 CONFIG_FREERTOS_HZ=1000
 # end of FREERTOS
 # end of Component config
+
+#
+# DIAGNOSTICS
+#
+CONFIG_DIAG_USE_EXTERNAL_LOG_WRAP=y

From 6cc7a63cd021e6cd457d086dc1efb6b550554c65 Mon Sep 17 00:00:00 2001
From: Wulu <wulu@wulu.zone>
Date: Mon, 28 Jul 2025 22:43:55 +0800
Subject: [PATCH 24/34] docs: Change ADC default resolution exception to
 ESP32-S2

---
 docs/en/api/adc.rst | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/docs/en/api/adc.rst b/docs/en/api/adc.rst
index 9c16db54ec1..416a8afd803 100644
--- a/docs/en/api/adc.rst
+++ b/docs/en/api/adc.rst
@@ -52,7 +52,8 @@ This function will return analog value in millivolts (calibrated).
 analogReadResolution
 ^^^^^^^^^^^^^^^^^^^^
 
-This function is used to set the resolution of ``analogRead`` return value. Default is 12 bits (range from 0 to 4095).
+This function is used to set the resolution of ``analogRead`` return value. Default is 12 bits (range from 0 to 4095)
+for all chips except ESP32-S2 where default is 13 bits (range from 0 to 8191).
 When different resolution is set, the values read will be shifted to match the given resolution.
 
 Range is 1 - 16 .The default value will be used, if this function is not used.

From f5b08cd81297136fbf0121835858bca39bd4d394 Mon Sep 17 00:00:00 2001
From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
Date: Mon, 28 Jul 2025 13:38:14 -0300
Subject: [PATCH 25/34] feat(codeql): Add CodeQL analysis for interpreted
 languages (#11662)

---
 .github/CODEOWNERS                   |  1 +
 .github/codeql/codeql-config.yml     | 26 +++++++++++++++++++++++
 .github/workflows/codeql_actions.yml | 31 ++++++++++++++++++++++++++++
 .github/workflows/codeql_python.yml  | 30 +++++++++++++++++++++++++++
 4 files changed, 88 insertions(+)
 create mode 100644 .github/codeql/codeql-config.yml
 create mode 100644 .github/workflows/codeql_actions.yml
 create mode 100644 .github/workflows/codeql_python.yml

diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 64d241ba20a..d07ef88044d 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -11,6 +11,7 @@
 
 # CI
 /.github/ @lucasssvaz @me-no-dev @P-R-O-C-H-Y
+/.github/codeql/ @lucasssvaz
 /.gitlab/ @lucasssvaz
 /tests/ @lucasssvaz @P-R-O-C-H-Y
 
diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml
new file mode 100644
index 00000000000..c640d7bd6ef
--- /dev/null
+++ b/.github/codeql/codeql-config.yml
@@ -0,0 +1,26 @@
+name: "CodeQL config"
+
+packs:
+  - trailofbits/cpp-queries
+  - githubsecuritylab/codeql-cpp-queries
+  - githubsecuritylab/codeql-python-queries
+
+queries:
+  - uses: security-extended
+  - uses: security-and-quality
+
+query-filters:
+  - exclude:
+      query path:
+        - /^experimental\/.*/
+  - exclude:
+      tags contain:
+        - experimental
+  - exclude:
+      problem.severity:
+        - recommendation
+  - exclude:
+      id: tob/cpp/use-of-legacy-algorithm
+
+paths-ignore:
+  - tests/**
diff --git a/.github/workflows/codeql_actions.yml b/.github/workflows/codeql_actions.yml
new file mode 100644
index 00000000000..07688f896ba
--- /dev/null
+++ b/.github/workflows/codeql_actions.yml
@@ -0,0 +1,31 @@
+name: CodeQL Actions Analysis
+
+on:
+  workflow_dispatch:
+  push:
+    branches:
+      - master
+  pull_request:
+    paths:
+      - ".github/workflows/*.yml"
+      - ".github/workflows/*.yaml"
+
+jobs:
+  codeql-analysis:
+    name: CodeQL Actions Analysis
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+      - name: Initialize CodeQL
+        uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
+        with:
+          languages: actions
+          config-file: ./.github/codeql/codeql-config.yml
+
+      - name: Run CodeQL Analysis
+        uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
+        with:
+          category: "Analysis: Actions"
diff --git a/.github/workflows/codeql_python.yml b/.github/workflows/codeql_python.yml
new file mode 100644
index 00000000000..312974cd3c1
--- /dev/null
+++ b/.github/workflows/codeql_python.yml
@@ -0,0 +1,30 @@
+name: CodeQL Python Analysis
+
+on:
+  workflow_dispatch:
+  push:
+    branches:
+      - master
+  pull_request:
+    paths:
+      - "**/*.py"
+
+jobs:
+  codeql-analysis:
+    name: CodeQL Python Analysis
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+      - name: Initialize CodeQL
+        uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
+        with:
+          languages: python
+          config-file: ./.github/codeql/codeql-config.yml
+
+      - name: Run CodeQL Analysis
+        uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
+        with:
+          category: "Analysis: Python"

From 18daf31211eaba8ea7108263a938c6672e4c036a Mon Sep 17 00:00:00 2001
From: Parsaabasi <mohammadabbasi970@gmail.com>
Date: Tue, 29 Jul 2025 14:22:58 +0200
Subject: [PATCH 26/34] fix(github-template): indentation

---
 .github/ISSUE_TEMPLATE/Issue-report.yml | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/Issue-report.yml b/.github/ISSUE_TEMPLATE/Issue-report.yml
index 864ef65b92b..e1c13413764 100644
--- a/.github/ISSUE_TEMPLATE/Issue-report.yml
+++ b/.github/ISSUE_TEMPLATE/Issue-report.yml
@@ -81,14 +81,14 @@ body:
     validations:
       required: true
  - type: dropdown
-    id: type
-    attributes:
-      label: Type
-      description: How would you define the type of the issue? Please select from the types below.
-      options:
-        - Task
-        - Bug
-        - Question
+   id: type
+   attributes:
+     label: Type
+     description: How would you define the type of the issue? Please select from the types below.
+     options:
+        - "Task"
+        - "Bug"
+        - "Question"
     validations:
       required: true
   - type: input

From 866359a0e38f726b539093237d6d688003f8ba96 Mon Sep 17 00:00:00 2001
From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
Date: Tue, 29 Jul 2025 11:54:40 -0300
Subject: [PATCH 27/34] fix(codeql): Merge CodeQL workflows to avoid errors in
 PRs

---
 .../{codeql_actions.yml => codeql.yml}        | 12 +++++---
 .github/workflows/codeql_python.yml           | 30 -------------------
 2 files changed, 8 insertions(+), 34 deletions(-)
 rename .github/workflows/{codeql_actions.yml => codeql.yml} (72%)
 delete mode 100644 .github/workflows/codeql_python.yml

diff --git a/.github/workflows/codeql_actions.yml b/.github/workflows/codeql.yml
similarity index 72%
rename from .github/workflows/codeql_actions.yml
rename to .github/workflows/codeql.yml
index 07688f896ba..fb0badd78ec 100644
--- a/.github/workflows/codeql_actions.yml
+++ b/.github/workflows/codeql.yml
@@ -1,4 +1,4 @@
-name: CodeQL Actions Analysis
+name: CodeQL Analysis
 
 on:
   workflow_dispatch:
@@ -7,13 +7,17 @@ on:
       - master
   pull_request:
     paths:
+      - "**/*.py"
       - ".github/workflows/*.yml"
       - ".github/workflows/*.yaml"
 
 jobs:
   codeql-analysis:
-    name: CodeQL Actions Analysis
+    name: CodeQL ${{ matrix.language }} analysis
     runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        language: [python, actions]
 
     steps:
       - name: Checkout repository
@@ -22,10 +26,10 @@ jobs:
       - name: Initialize CodeQL
         uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
         with:
-          languages: actions
+          languages: ${{ matrix.language }}
           config-file: ./.github/codeql/codeql-config.yml
 
       - name: Run CodeQL Analysis
         uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
         with:
-          category: "Analysis: Actions"
+          category: "/language:${{ matrix.language }}"
diff --git a/.github/workflows/codeql_python.yml b/.github/workflows/codeql_python.yml
deleted file mode 100644
index 312974cd3c1..00000000000
--- a/.github/workflows/codeql_python.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-name: CodeQL Python Analysis
-
-on:
-  workflow_dispatch:
-  push:
-    branches:
-      - master
-  pull_request:
-    paths:
-      - "**/*.py"
-
-jobs:
-  codeql-analysis:
-    name: CodeQL Python Analysis
-    runs-on: ubuntu-latest
-
-    steps:
-      - name: Checkout repository
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
-      - name: Initialize CodeQL
-        uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
-        with:
-          languages: python
-          config-file: ./.github/codeql/codeql-config.yml
-
-      - name: Run CodeQL Analysis
-        uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
-        with:
-          category: "Analysis: Python"

From 4eff7f9ae408a9fdd5d15c86184bda785d881aa3 Mon Sep 17 00:00:00 2001
From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
Date: Tue, 29 Jul 2025 14:43:25 -0300
Subject: [PATCH 28/34] fix(template): Fix issue report template

---
 .github/ISSUE_TEMPLATE/Issue-report.yml | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/Issue-report.yml b/.github/ISSUE_TEMPLATE/Issue-report.yml
index e1c13413764..97834925020 100644
--- a/.github/ISSUE_TEMPLATE/Issue-report.yml
+++ b/.github/ISSUE_TEMPLATE/Issue-report.yml
@@ -80,12 +80,12 @@ body:
         - other
     validations:
       required: true
- - type: dropdown
-   id: type
-   attributes:
-     label: Type
-     description: How would you define the type of the issue? Please select from the types below.
-     options:
+  - type: dropdown
+    id: type
+    attributes:
+      label: Type
+      description: How would you define the type of the issue? Please select from the types below.
+      options:
         - "Task"
         - "Bug"
         - "Question"

From 2b9d7576fa918e3f27ebd743690489c0874c2309 Mon Sep 17 00:00:00 2001
From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
Date: Wed, 30 Jul 2025 10:27:31 -0300
Subject: [PATCH 29/34] ci(component): Move component compilation to a separate
 workflow

---
 .github/scripts/set_push_chunks.sh    |   1 -
 .github/workflows/build_component.yml | 133 ++++++++++++++++++++++++++
 .github/workflows/push.yml            | 120 +++++------------------
 .github/workflows/tests.yml           |  11 +--
 4 files changed, 159 insertions(+), 106 deletions(-)
 create mode 100644 .github/workflows/build_component.yml

diff --git a/.github/scripts/set_push_chunks.sh b/.github/scripts/set_push_chunks.sh
index ff0af7da6e8..69cd9a7f7de 100644
--- a/.github/scripts/set_push_chunks.sh
+++ b/.github/scripts/set_push_chunks.sh
@@ -78,7 +78,6 @@ chunks+="]"
     echo "build_all=$build_all"
     echo "build_libraries=$BUILD_LIBRARIES"
     echo "build_static_sketches=$BUILD_STATIC_SKETCHES"
-    echo "build_idf=$BUILD_IDF"
     echo "chunk_count=$chunks_count"
     echo "chunks=$chunks"
 } >> "$GITHUB_OUTPUT"
diff --git a/.github/workflows/build_component.yml b/.github/workflows/build_component.yml
new file mode 100644
index 00000000000..5553b4b2024
--- /dev/null
+++ b/.github/workflows/build_component.yml
@@ -0,0 +1,133 @@
+name: Arduino as ESP-IDF Component
+
+on:
+  workflow_dispatch:
+    inputs:
+      idf_ver:
+        description: "IDF Versions"
+        default: "release-v5.3,release-v5.4,release-v5.5"
+        type: "string"
+        required: true
+      idf_targets:
+        description: "IDF Targets"
+        default: "esp32,esp32s2,esp32s3,esp32c2,esp32c3,esp32c6,esp32h2,esp32p4"
+        type: "string"
+        required: true
+  push:
+    branches:
+      - master
+      - release/*
+  pull_request:
+    paths:
+      - "cores/**"
+      - "libraries/**/*.cpp"
+      - "libraries/**/*.c"
+      - "libraries/**/*.h"
+      - "libraries/**/*.ino"
+      - "libraries/**/ci.json"
+      - "idf_component_examples/**"
+      - "idf_component.yml"
+      - "Kconfig.projbuild"
+      - "CMakeLists.txt"
+      - ".github/workflows/build_component.yml"
+      - ".github/scripts/check-cmakelists.sh"
+      - ".github/scripts/on-push-idf.sh"
+      - ".github/scripts/sketch_utils.sh"
+      - "variants/esp32/**"
+      - "variants/esp32c2/**"
+      - "variants/esp32c3/**"
+      - "variants/esp32c6/**"
+      - "variants/esp32h2/**"
+      - "variants/esp32p4/**"
+      - "variants/esp32s2/**"
+      - "variants/esp32s3/**"
+      - "!*.md"
+      - "!*.txt"
+      - "!*.properties"
+
+concurrency:
+  group: build-component-${{github.event.pull_request.number || github.ref}}
+  cancel-in-progress: true
+
+jobs:
+  cmake-check:
+    name: Check CMakeLists
+    runs-on: ubuntu-latest
+    if: ${{ !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'release/')) }}
+    steps:
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+      - run: bash ./.github/scripts/check-cmakelists.sh
+
+  set-matrix:
+    name: Set Matrix
+    runs-on: ubuntu-latest
+    if: ${{ !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'release/')) }}
+    outputs:
+      idf_ver: ${{ steps.set-matrix.outputs.idf_ver }}
+      idf_target: ${{ steps.set-matrix.outputs.idf_target }}
+    steps:
+      - name: Get IDF Version and Targets
+        id: set-matrix
+        run: |
+          # Default values
+          idf_ver="release-v5.3,release-v5.4,release-v5.5"
+          idf_targets="esp32,esp32s2,esp32s3,esp32c2,esp32c3,esp32c6,esp32h2,esp32p4"
+
+          # Override with inputs if provided
+          if [[ -n "${{ inputs.idf_ver }}" ]]; then
+            idf_ver="${{ inputs.idf_ver }}"
+          fi
+          if [[ -n "${{ inputs.idf_targets }}" ]]; then
+            idf_targets="${{ inputs.idf_targets }}"
+          fi
+
+          # Convert comma-separated strings to JSON arrays using a more robust method
+          idf_ver_json=$(printf '%s\n' "$idf_ver" | tr ',' '\n' | jq -R . | jq -s . | jq -c .)
+          idf_targets_json=$(printf '%s\n' "$idf_targets" | tr ',' '\n' | jq -R . | jq -s . | jq -c .)
+
+          # Debug: Print the JSON for verification
+          echo "Debug - idf_ver_json: $idf_ver_json"
+          echo "Debug - idf_targets_json: $idf_targets_json"
+
+          # Set outputs - ensure no extra whitespace
+          printf "idf_ver=%s\n" "$idf_ver_json" >> $GITHUB_OUTPUT
+          printf "idf_target=%s\n" "$idf_targets_json" >> $GITHUB_OUTPUT
+
+  build-esp-idf-component:
+    name: Build IDF ${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
+    runs-on: ubuntu-latest
+    needs: set-matrix
+    strategy:
+      fail-fast: false
+      matrix:
+        # The version names here correspond to the versions of espressif/idf Docker image.
+        # See https://hub.docker.com/r/espressif/idf/tags and
+        # https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-docker-image.html
+        # for details.
+        idf_ver: ${{ fromJson(needs.set-matrix.outputs.idf_ver) }}
+        idf_target: ${{ fromJson(needs.set-matrix.outputs.idf_target) }}
+    container: espressif/idf:${{ matrix.idf_ver }}
+    steps:
+      - name: Check out arduino-esp32 as a component
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+        with:
+          submodules: recursive
+          path: components/arduino-esp32
+
+      - name: Setup jq
+        uses: dcarbone/install-jq-action@e397bd87438d72198f81efd21f876461183d383a # v3.0.1
+
+      - name: Build
+        env:
+          IDF_TARGET: ${{ matrix.idf_target }}
+        shell: bash
+        run: |
+          chmod a+x ./components/arduino-esp32/.github/scripts/*
+          ./components/arduino-esp32/.github/scripts/on-push-idf.sh
+
+      - name: Upload generated sdkconfig files for debugging
+        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+        if: always()
+        with:
+          name: sdkconfig-${{ matrix.idf_ver }}-${{ matrix.idf_target }}
+          path: ./components/arduino-esp32/idf_component_examples/**/sdkconfig
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 1523b7231be..fc85566aa8b 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -25,34 +25,32 @@ on:
   pull_request:
     paths:
       - "cores/**"
-      - "libraries/**"
-      - "!libraries/**.md"
-      - "!libraries/**.txt"
-      - "!libraries/**.properties"
-      - "!libraries/**.py"
+      - "libraries/**/*.cpp"
+      - "libraries/**/*.c"
+      - "libraries/**/*.h"
+      - "libraries/**/*.ino"
+      - "libraries/**/ci.json"
       - "package/**"
-      - "idf_component_examples/**"
-      - "tools/**.py"
+      - "tools/get.*"
       - "platform.txt"
       - "programmers.txt"
-      - "idf_component.yml"
-      - "Kconfig.projbuild"
       - "package.json"
-      - "CMakeLists.txt"
       - ".github/workflows/push.yml"
-      - ".github/scripts/**"
-      - "!.github/scripts/find_*"
-      - "!.github/scripts/on-release.sh"
-      - "!.github/scripts/tests_*"
-      - "!.github/scripts/upload_*"
-      - "variants/esp32/**/*"
-      - "variants/esp32c3/**/*"
-      - "variants/esp32c5/**/*"
-      - "variants/esp32c6/**/*"
-      - "variants/esp32h2/**/*"
-      - "variants/esp32p4/**/*"
-      - "variants/esp32s2/**/*"
-      - "variants/esp32s3/**/*"
+      - ".github/scripts/install-*"
+      - ".github/scripts/on-push.sh"
+      - ".github/scripts/set_push_chunks.sh"
+      - ".github/scripts/sketch_utils.sh"
+      - "variants/esp32/**"
+      - "variants/esp32c3/**"
+      - "variants/esp32c5/**"
+      - "variants/esp32c6/**"
+      - "variants/esp32h2/**"
+      - "variants/esp32p4/**"
+      - "variants/esp32s2/**"
+      - "variants/esp32s3/**"
+      - "!*.md"
+      - "!*.txt"
+      - "!*.properties"
 
 concurrency:
   group: build-${{github.event.pull_request.number || github.ref}}
@@ -62,14 +60,6 @@ env:
   MAX_CHUNKS: 15
 
 jobs:
-  cmake-check:
-    name: Check cmake file
-    runs-on: ubuntu-latest
-    if: ${{ !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'release/')) }}
-    steps:
-      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-      - run: bash ./.github/scripts/check-cmakelists.sh
-
   gen-chunks:
     name: Generate chunks
     runs-on: ubuntu-latest
@@ -78,7 +68,6 @@ jobs:
       build_all: ${{ steps.set-chunks.outputs.build_all }}
       build_libraries: ${{ steps.set-chunks.outputs.build_libraries }}
       build_static_sketches: ${{ steps.set-chunks.outputs.build_static_sketches }}
-      build_idf: ${{ steps.set-chunks.outputs.build_idf }}
       chunk_count: ${{ steps.set-chunks.outputs.chunk_count }}
       chunks: ${{ steps.set-chunks.outputs.chunks }}
     steps:
@@ -99,13 +88,7 @@ jobs:
               - 'tools/**'
               - 'platform.txt'
               - 'programmers.txt'
-              - "variants/esp32/**/*"
-              - "variants/esp32c3/**/*"
-              - "variants/esp32c6/**/*"
-              - "variants/esp32h2/**/*"
-              - "variants/esp32p4/**/*"
-              - "variants/esp32s2/**/*"
-              - "variants/esp32s3/**/*"
+              - "variants/**"
             libraries:
               - 'libraries/**/examples/**'
               - 'libraries/**/src/**'
@@ -121,11 +104,6 @@ jobs:
               - 'libraries/NetworkClientSecure/src/**'
               - 'libraries/BLE/src/**'
               - 'libraries/Insights/src/**'
-            idf:
-              - 'idf_component.yml'
-              - 'Kconfig.projbuild'
-              - 'CMakeLists.txt'
-              - "idf_component_examples/**"
 
       - name: Set chunks
         id: set-chunks
@@ -133,7 +111,6 @@ jobs:
           LIB_FILES: ${{ steps.changed-files.outputs.libraries_all_changed_files }}
           IS_PR: ${{ github.event_name == 'pull_request' }}
           MAX_CHUNKS: ${{ env.MAX_CHUNKS }}
-          BUILD_IDF: ${{ steps.changed-files.outputs.idf_any_changed == 'true' }}
           BUILD_LIBRARIES: ${{ steps.changed-files.outputs.libraries_any_changed == 'true' }}
           BUILD_STATIC_SKETCHES: ${{ steps.changed-files.outputs.static_sketeches_any_changed == 'true' }}
           FS_CHANGED: ${{ steps.changed-files.outputs.fs_any_changed == 'true' }}
@@ -233,59 +210,6 @@ jobs:
       - name: Build Sketches
         run: bash ./.github/scripts/on-push.sh
 
-  build-esp-idf-component:
-    name: Build with ESP-IDF ${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
-    needs: gen-chunks
-    if: |
-      needs.gen-chunks.outputs.build_all == 'true' ||
-      needs.gen-chunks.outputs.build_libraries == 'true' ||
-      needs.gen-chunks.outputs.build_idf == 'true'
-    runs-on: ubuntu-latest
-    strategy:
-      fail-fast: false
-      matrix:
-        # The version names here correspond to the versions of espressif/idf Docker image.
-        # See https://hub.docker.com/r/espressif/idf/tags and
-        # https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-docker-image.html
-        # for details.
-        idf_ver: ["release-v5.3","release-v5.4","release-v5.5"]
-        idf_target:
-          [
-            "esp32",
-            "esp32s2",
-            "esp32s3",
-            "esp32c2",
-            "esp32c3",
-            "esp32c6",
-            "esp32h2",
-            "esp32p4"
-          ]
-    container: espressif/idf:${{ matrix.idf_ver }}
-    steps:
-      - name: Check out arduino-esp32 as a component
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-        with:
-          submodules: recursive
-          path: components/arduino-esp32
-
-      - name: Setup jq
-        uses: dcarbone/install-jq-action@e397bd87438d72198f81efd21f876461183d383a # v3.0.1
-
-      - name: Build
-        env:
-          IDF_TARGET: ${{ matrix.idf_target }}
-        shell: bash
-        run: |
-          chmod a+x ./components/arduino-esp32/.github/scripts/*
-          ./components/arduino-esp32/.github/scripts/on-push-idf.sh
-
-      - name: Upload generated sdkconfig files for debugging
-        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
-        if: always()
-        with:
-          name: sdkconfig-${{ matrix.idf_ver }}-${{ matrix.idf_target }}
-          path: ./components/arduino-esp32/idf_component_examples/**/sdkconfig
-
   # Save artifacts to gh-pages
   save-master-artifacts:
     name: Save master artifacts
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index ddc9b64aace..058d9a3a793 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -16,20 +16,17 @@ on:
   pull_request:
     types: [opened, reopened, closed, synchronize, labeled, unlabeled]
     paths:
+      - ".github/scripts/install*.sh"
       - ".github/workflows/tests*"
-      - ".github/scripts/*.sh"
-      - "!.github/scripts/check-cmakelists.sh"
-      - "!.github/scripts/find_*"
-      - "!.github/scripts/on-*.sh"
-      - "!.github/scripts/set_push_chunks.sh"
-      - "!.github/scripts/update-version.sh"
-      - "!.github/scripts/upload_py_tools.sh"
+      - ".github/scripts/sketch_utils.sh"
       - "tests/**"
       - "cores/**"
       - "libraries/*/src/**.cpp"
       - "libraries/*/src/**.h"
       - "libraries/*/src/**.c"
       - "package/**"
+      - "!*.md"
+      - "!*.properties"
   schedule:
     - cron: "0 2 * * *"
 

From b9c0f689ae3bdb7e40cc34b69ae2a8681a060af5 Mon Sep 17 00:00:00 2001
From: wulu <wulu@wulu.zone>
Date: Wed, 30 Jul 2025 22:36:29 +0800
Subject: [PATCH 30/34] docs: Specify ADC resolution errata for ESP32-S2 v0.0

---
 docs/en/api/adc.rst | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/docs/en/api/adc.rst b/docs/en/api/adc.rst
index 416a8afd803..f2245cc1e5d 100644
--- a/docs/en/api/adc.rst
+++ b/docs/en/api/adc.rst
@@ -52,10 +52,12 @@ This function will return analog value in millivolts (calibrated).
 analogReadResolution
 ^^^^^^^^^^^^^^^^^^^^
 
-This function is used to set the resolution of ``analogRead`` return value. Default is 12 bits (range from 0 to 4095)
-for all chips except ESP32-S2 where default is 13 bits (range from 0 to 8191).
+This function is used to set the resolution of ``analogRead`` return value. Default is 12 bits (range from 0 to 4095) for all chips.
 When different resolution is set, the values read will be shifted to match the given resolution.
 
+.. note::
+   For **ESP32-S2 chip revision v0.0**, the default ADC resolution is 13 bits (0-8191) due to the `ADC-112 errata <https://docs.espressif.com/projects/esp-chip-errata/en/latest/esp32s2/03-errata-description/esp32s2/sar-adc-bit1-no-flip.html>`_. This is fixed in later revisions (v1.0+), which use the standard 12-bit resolution.
+
 Range is 1 - 16 .The default value will be used, if this function is not used.
 
 .. note:: For the ESP32, the resolution is between 9 to12 and it will change the ADC hardware resolution. Else value will be shifted.

From 673048f73e41cfddccfdbc676f38f7ff7b146dfc Mon Sep 17 00:00:00 2001
From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
Date: Thu, 31 Jul 2025 08:21:11 -0300
Subject: [PATCH 31/34] change(esptool): Upgrade esptool to 5.0.2

---
 package/package_esp32_index.template.json | 60 +++++++++++------------
 1 file changed, 30 insertions(+), 30 deletions(-)

diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json
index 3909c833c56..1b4b005dd34 100644
--- a/package/package_esp32_index.template.json
+++ b/package/package_esp32_index.template.json
@@ -81,7 +81,7 @@
             {
               "packager": "esp32",
               "name": "esptool_py",
-              "version": "5.0.0"
+              "version": "5.0.2"
             },
             {
               "packager": "esp32",
@@ -469,56 +469,56 @@
         },
         {
           "name": "esptool_py",
-          "version": "5.0.0",
+          "version": "5.0.2",
           "systems": [
             {
               "host": "aarch64-linux-gnu",
-              "url": "https://github.com/espressif/esptool/releases/download/v5.0.0/esptool-v5.0.0-linux-aarch64.tar.gz",
-              "archiveFileName": "esptool-v5.0.0-linux-aarch64.tar.gz",
-              "checksum": "SHA-256:2bf239f3ed76141a957cadb205b94414ec6da9ace4e85f285e247d20a92b83e3",
-              "size": "58231895"
+              "url": "https://github.com/espressif/esptool/releases/download/v5.0.2/esptool-v5.0.2-linux-aarch64.tar.gz",
+              "archiveFileName": "esptool-v5.0.2-linux-aarch64.tar.gz",
+              "checksum": "SHA-256:0c1fa4f5e96f715133fa65572063fa65bd120cd941b667cecd3360436a62b97b",
+              "size": "57815944"
             },
             {
               "host": "x86_64-pc-linux-gnu",
-              "url": "https://github.com/espressif/esptool/releases/download/v5.0.0/esptool-v5.0.0-linux-amd64.tar.gz",
-              "archiveFileName": "esptool-v5.0.0-linux-amd64.tar.gz",
-              "checksum": "SHA-256:3b3835d266ac61f3242758f2fe34e3b33dbe6ee4b5acde005da793356f9f7043",
-              "size": "100783748"
+              "url": "https://github.com/espressif/esptool/releases/download/v5.0.2/esptool-v5.0.2-linux-amd64.tar.gz",
+              "archiveFileName": "esptool-v5.0.2-linux-amd64.tar.gz",
+              "checksum": "SHA-256:519e0015872d527bdca850b18575d4f635fa88ccdffe47a14c99a80a90b780c5",
+              "size": "100787554"
             },
             {
               "host": "arm-linux-gnueabihf",
-              "url": "https://github.com/espressif/esptool/releases/download/v5.0.0/esptool-v5.0.0-linux-armv7.tar.gz",
-              "archiveFileName": "esptool-v5.0.0-linux-armv7.tar.gz",
-              "checksum": "SHA-256:e55cd321abecfcf27f72a2bff5d5e19a5365fd400de66d71c5e7218e77556315",
-              "size": "53461760"
+              "url": "https://github.com/espressif/esptool/releases/download/v5.0.2/esptool-v5.0.2-linux-armv7.tar.gz",
+              "archiveFileName": "esptool-v5.0.2-linux-armv7.tar.gz",
+              "checksum": "SHA-256:8df698d46a64b0b4a36d2a5bbd6bae58f81ca0a5e6451cd3f2d69a33340cc0f1",
+              "size": "53046401"
             },
             {
               "host": "x86_64-apple-darwin",
-              "url": "https://github.com/espressif/esptool/releases/download/v5.0.0/esptool-v5.0.0-macos-amd64.tar.gz",
-              "archiveFileName": "esptool-v5.0.0-macos-amd64.tar.gz",
-              "checksum": "SHA-256:424da2bdf0435257ad81bcb7eae6fd8dd7f675ce5b2ee60032f4ecec4d6a5d45",
-              "size": "59629533"
+              "url": "https://github.com/espressif/esptool/releases/download/v5.0.2/esptool-v5.0.2-macos-amd64.tar.gz",
+              "archiveFileName": "esptool-v5.0.2-macos-amd64.tar.gz",
+              "checksum": "SHA-256:5c27295975515b97a9280f46845bd3acd5fc9e6a0583cfe03efa66cc50195ab0",
+              "size": "59619952"
             },
             {
               "host": "arm64-apple-darwin",
-              "url": "https://github.com/espressif/esptool/releases/download/v5.0.0/esptool-v5.0.0-macos-arm64.tar.gz",
-              "archiveFileName": "esptool-v5.0.0-macos-arm64.tar.gz",
-              "checksum": "SHA-256:b91dfe1da7b0041376683dec10a91dfb266fbda2fb86ed87c4a034ff7182ee56",
-              "size": "56343104"
+              "url": "https://github.com/espressif/esptool/releases/download/v5.0.2/esptool-v5.0.2-macos-arm64.tar.gz",
+              "archiveFileName": "esptool-v5.0.2-macos-arm64.tar.gz",
+              "checksum": "SHA-256:93f0d9ef169f9bc6e32ed6f381977f63a5df7483b8002a5676dddf055bdbf775",
+              "size": "56344929"
             },
             {
               "host": "x86_64-mingw32",
-              "url": "https://github.com/espressif/esptool/releases/download/v5.0.0/esptool-v5.0.0-windows-amd64.zip",
-              "archiveFileName": "esptool-v5.0.0-windows-amd64.zip",
-              "checksum": "SHA-256:2294107f66db6f09b886b337728a981173c9e7eab45a030928a8a5a1370611ca",
-              "size": "59105322"
+              "url": "https://github.com/espressif/esptool/releases/download/v5.0.2/esptool-v5.0.2-windows-amd64.zip",
+              "archiveFileName": "esptool-v5.0.2-windows-amd64.zip",
+              "checksum": "SHA-256:1caef993a16c5915714a0da772d93f2e3239f316c06223981b262b838287268c",
+              "size": "59097582"
             },
             {
               "host": "i686-mingw32",
-              "url": "https://github.com/espressif/esptool/releases/download/v5.0.0/esptool-v5.0.0-windows-amd64.zip",
-              "archiveFileName": "esptool-v5.0.0-windows-amd64.zip",
-              "checksum": "SHA-256:2294107f66db6f09b886b337728a981173c9e7eab45a030928a8a5a1370611ca",
-              "size": "59105322"
+              "url": "https://github.com/espressif/esptool/releases/download/v5.0.2/esptool-v5.0.2-windows-amd64.zip",
+              "archiveFileName": "esptool-v5.0.2-windows-amd64.zip",
+              "checksum": "SHA-256:1caef993a16c5915714a0da772d93f2e3239f316c06223981b262b838287268c",
+              "size": "59097582"
             }
           ]
         },

From 30847588bc8909334479e4ee1ba48f43d051f8d0 Mon Sep 17 00:00:00 2001
From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
Date: Thu, 31 Jul 2025 21:50:52 -0300
Subject: [PATCH 32/34] feat(codeql): Add CPP analysis

---
 .github/scripts/process_sarif.py | 129 +++++++++++++++++++++++++++++++
 .github/workflows/codeql.yml     |  55 ++++++++++++-
 2 files changed, 183 insertions(+), 1 deletion(-)
 create mode 100644 .github/scripts/process_sarif.py

diff --git a/.github/scripts/process_sarif.py b/.github/scripts/process_sarif.py
new file mode 100644
index 00000000000..fad689b6390
--- /dev/null
+++ b/.github/scripts/process_sarif.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python3
+
+# This script is used to process the SARIF file generated by CodeQL and
+# to rename files back to .ino and adjust line numbers to match the original .ino files.
+
+import json
+import sys
+import os
+
+def process_artifact_location(artifact_location, renamed_files):
+    """
+    Process a single artifact location to rename .cpp files back to .ino
+    """
+    if 'uri' in artifact_location:
+        uri = artifact_location['uri']
+        if uri in renamed_files:
+            print(f"Renaming file: {uri} -> {renamed_files[uri]}")
+            artifact_location['uri'] = renamed_files[uri]
+            return True
+    return False
+
+def process_region(region):
+    """
+    Adjust line numbers in a region by decreasing them by 1
+    """
+    if 'startLine' in region:
+        region['startLine'] = max(1, region['startLine'] - 1)
+    if 'endLine' in region:
+        region['endLine'] = max(1, region['endLine'] - 1)
+
+def process_physical_location(physical_location, renamed_files):
+    """
+    Process a physical location to rename files and adjust line numbers
+    """
+    file_renamed = False
+
+    if 'artifactLocation' in physical_location:
+        if process_artifact_location(physical_location['artifactLocation'], renamed_files):
+            file_renamed = True
+
+    # Adjust line numbers if the file was renamed
+    if file_renamed and 'region' in physical_location:
+        process_region(physical_location['region'])
+
+    return file_renamed
+
+
+def process_sarif_file(sarif_file, renamed_files_file):
+    """
+    Process SARIF file to rename files back to .ino and adjust line numbers
+    """
+    # Read the renamed files mapping
+    with open(renamed_files_file, 'r') as f:
+        renamed_files = json.load(f)
+
+    print(f"Loaded {len(renamed_files)} file mappings:")
+    for cpp_file, ino_file in renamed_files.items():
+        print(f"  {cpp_file} -> {ino_file}")
+
+
+    # Read the SARIF file
+    with open(sarif_file, 'r') as f:
+        sarif_data = json.load(f)
+
+    files_processed = 0
+
+    # Process each run
+    if 'runs' in sarif_data:
+        for run in sarif_data['runs']:
+            # Process results
+            if 'results' in run:
+                for result in run['results']:
+                    # Process all locations in the result
+                    if 'locations' in result:
+                        for location in result['locations']:
+                            if 'physicalLocation' in location:
+                                if process_physical_location(location['physicalLocation'], renamed_files):
+                                    files_processed += 1
+
+                    # Process related locations if they exist
+                    if 'relatedLocations' in result:
+                        for location in result['relatedLocations']:
+                            if 'physicalLocation' in location:
+                                if process_physical_location(location['physicalLocation'], renamed_files):
+                                    files_processed += 1
+
+            # Process artifacts if they exist
+            if 'artifacts' in run:
+                for artifact in run['artifacts']:
+                    if 'location' in artifact and 'uri' in artifact['location']:
+                        uri = artifact['location']['uri']
+                        if uri in renamed_files:
+                            artifact['location']['uri'] = renamed_files[uri]
+                            files_processed += 1
+
+    print(f"Processed {files_processed} file references")
+
+    # Write the processed SARIF file
+    with open(sarif_file, 'w') as f:
+        json.dump(sarif_data, f, indent=2)
+
+def main():
+    if len(sys.argv) != 3:
+        print("Usage: python3 sarif_nobuild.py <sarif_file> <renamed_files_file>")
+        sys.exit(1)
+
+    sarif_file = sys.argv[1]
+    renamed_files_file = sys.argv[2]
+
+    # Check if files exist
+    if not os.path.exists(sarif_file):
+        print(f"SARIF file not found: {sarif_file}")
+        sys.exit(1)
+
+    if not os.path.exists(renamed_files_file):
+        print(f"Renamed files mapping not found: {renamed_files_file}")
+        sys.exit(1)
+
+    try:
+        process_sarif_file(sarif_file, renamed_files_file)
+        print("SARIF file processed successfully")
+    except Exception as e:
+        print(f"Error processing SARIF file: {e}")
+        import traceback
+        traceback.print_exc()
+        sys.exit(1)
+
+if __name__ == "__main__":
+    main()
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index fb0badd78ec..9b2c6bccab1 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -7,6 +7,10 @@ on:
       - master
   pull_request:
     paths:
+      - "**/*.c"
+      - "**/*.cpp"
+      - "**/*.h"
+      - "**/*.ino"
       - "**/*.py"
       - ".github/workflows/*.yml"
       - ".github/workflows/*.yaml"
@@ -17,15 +21,48 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        language: [python, actions]
+        language: [python, actions, cpp]
 
     steps:
       - name: Checkout repository
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
 
+      - name: Process .ino files
+        if: matrix.language == 'cpp'
+        run: |
+          # Create a mapping file to track renamed files
+          echo "{}" > renamed_files.json
+
+          # Find all .ino files and process them
+          find . -name "*.ino" -type f | while read -r file; do
+            echo "Processing $file"
+
+            # Get the relative path from repository root
+            rel_path=$(realpath --relative-to=. "$file")
+            cpp_path="${rel_path%.ino}.cpp"
+
+            # Create new .cpp file with Arduino.h include
+            echo "#include <Arduino.h>" > "$cpp_path"
+
+            # Append the original content
+            cat "$file" >> "$cpp_path"
+
+            # Update the mapping file
+            jq --arg ino "$rel_path" --arg cpp "$cpp_path" '. += {($cpp): $ino}' renamed_files.json > temp.json && mv temp.json renamed_files.json
+
+            # Remove the original .ino file
+            rm "$file"
+
+            echo "Converted $file to $cpp_path"
+          done
+
+          echo "Renamed files mapping:"
+          cat renamed_files.json
+
       - name: Initialize CodeQL
         uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
         with:
+          build-mode: none
           languages: ${{ matrix.language }}
           config-file: ./.github/codeql/codeql-config.yml
 
@@ -33,3 +70,19 @@ jobs:
         uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
         with:
           category: "/language:${{ matrix.language }}"
+          output: sarif-results
+          upload: failure-only
+
+      - name: Process SARIF file
+        if: matrix.language == 'cpp'
+        run: |
+          sarif_file="sarif-results/${{ matrix.language }}.sarif"
+
+          # Run the Python script to process the SARIF file
+          python3 .github/scripts/process_sarif.py "$sarif_file" "renamed_files.json"
+
+      - name: Upload SARIF file
+        uses: github/codeql-action/upload-sarif@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
+        with:
+          sarif_file: sarif-results/${{ matrix.language }}.sarif
+          category: "/language:${{ matrix.language }}"

From 81cc594e63f50d5f3c2045b0cb069f06ff46fc27 Mon Sep 17 00:00:00 2001
From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
Date: Sun, 3 Aug 2025 17:32:18 -0300
Subject: [PATCH 33/34] fix(push): Fix typo in yaml

---
 .github/workflows/push.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index fc85566aa8b..48530e30bc9 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -96,7 +96,7 @@ jobs:
               - 'libraries/Network/src/**'
             fs:
               - 'libraries/FS/src/**'
-            static_sketeches:
+            static_sketches:
               - 'libraries/NetworkClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino'
               - 'libraries/BLE/examples/Server/Server.ino'
               - 'libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino'
@@ -112,7 +112,7 @@ jobs:
           IS_PR: ${{ github.event_name == 'pull_request' }}
           MAX_CHUNKS: ${{ env.MAX_CHUNKS }}
           BUILD_LIBRARIES: ${{ steps.changed-files.outputs.libraries_any_changed == 'true' }}
-          BUILD_STATIC_SKETCHES: ${{ steps.changed-files.outputs.static_sketeches_any_changed == 'true' }}
+          BUILD_STATIC_SKETCHES: ${{ steps.changed-files.outputs.static_sketches_any_changed == 'true' }}
           FS_CHANGED: ${{ steps.changed-files.outputs.fs_any_changed == 'true' }}
           NETWORKING_CHANGED: ${{ steps.changed-files.outputs.networking_any_changed == 'true' }}
           CORE_CHANGED: ${{ steps.changed-files.outputs.core_any_changed == 'true' }}

From f6b1910e8ba5a9aff99fa00b2133b10f34f85e4f Mon Sep 17 00:00:00 2001
From: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
Date: Fri, 8 Aug 2025 10:22:19 -0300
Subject: [PATCH 34/34] fix(codeql): Remove rule causing false positives

---
 .github/codeql/codeql-config.yml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml
index c640d7bd6ef..1c284c9d68e 100644
--- a/.github/codeql/codeql-config.yml
+++ b/.github/codeql/codeql-config.yml
@@ -20,7 +20,9 @@ query-filters:
       problem.severity:
         - recommendation
   - exclude:
-      id: tob/cpp/use-of-legacy-algorithm
+      id: tob/cpp/use-of-legacy-algorithm # We use legacy algorithms in many places for integrity checks
+  - exclude:
+      id: cpp/dead-code-goto # Too many false positives in no-build mode
 
 paths-ignore:
   - tests/**
