Skip to content

fix(board): Update variant.cpp for senseBox MCU-S2 ESP32-S2 #11532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion boards.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40993,7 +40993,7 @@ sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2=TinyUF2 4MB (1.3MB APP/960KB F
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.build.custom_bootloader=bootloader-tinyuf2
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.build.custom_partitions=partitions-4MB-tinyuf2
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.upload.maximum_size=1441792
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.upload.extra_flags=0x2d0000 "{runtime.platform.path}/variants/{build.variant}/tinyuf2.bin"
sensebox_mcu_esp32s2.menu.PartitionScheme.tinyuf2.upload.extra_flags=0x2d0000 "{runtime.platform.path}/variants/{build.variant}/tinyuf2.bin" 0x170000 "{runtime.platform.path}/variants/{build.variant}/APOTA.bin"
sensebox_mcu_esp32s2.menu.PartitionScheme.default=Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
sensebox_mcu_esp32s2.menu.PartitionScheme.default.build.partitions=default
sensebox_mcu_esp32s2.menu.PartitionScheme.defaultffat=Default 4MB with ffat (1.2MB APP/1.5MB FATFS)
Expand Down
Binary file added variants/sensebox_mcu_esp32s2/APOTA.bin
Binary file not shown.
283 changes: 283 additions & 0 deletions variants/sensebox_mcu_esp32s2/APOTA.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
#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();
}
}
74 changes: 47 additions & 27 deletions variants/sensebox_mcu_esp32s2/variant.cpp
Original file line number Diff line number Diff line change
@@ -1,29 +1,10 @@
/*
* 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 "esp_partition.h"
#include "esp_system.h"
#include "esp_ota_ops.h"
#include "esp_log.h"
#include <esp_chip_info.h>

extern "C" {

Expand All @@ -41,12 +22,51 @@ void initVariant(void) {
pinMode(PIN_XB1_ENABLE, OUTPUT);
digitalWrite(PIN_XB1_ENABLE, LOW);

//enable UART by default
pinMode(PIN_UART_ENABLE, OUTPUT);
digitalWrite(PIN_UART_ENABLE, LOW);
//enable UART only for chip without PSRAM
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
if (chip_info.revision <= 0) {
pinMode(PIN_UART_ENABLE, OUTPUT);
digitalWrite(PIN_UART_ENABLE, LOW);
}

//enable PD-Sensor by default
pinMode(PD_ENABLE, OUTPUT);
digitalWrite(PD_ENABLE, HIGH);

// define button pin
const int PIN_BUTTON = 0;
pinMode(PIN_BUTTON, INPUT_PULLUP);

// keep button pressed
unsigned long pressStartTime = 0;
bool buttonPressed = false;

// Wait 5 seconds for the button to be pressed
unsigned long startTime = millis();

// Check if button is pressed
while (millis() - startTime < 5000) {
if (digitalRead(PIN_BUTTON) == 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) {
esp_restart(); // restart, to boot OTA1 partition
} else {
ESP_LOGE("OTA", "Error setting OTA1 partition: %s", esp_err_to_name(err));
}
}
// Abort after releasing the button
break;
}
}
}
}