1
+ #define DISPLAY_ENABLED
2
+
3
+ #include < WiFi.h>
4
+ #include < WebServer.h>
5
+ #include < ESPmDNS.h>
6
+ #include < WiFiAP.h>
7
+ #include < Update.h>
8
+ #include < Wire.h>
9
+ #ifdef DISPLAY_ENABLED
10
+ #define SCREEN_WIDTH 128
11
+ #define SCREEN_HEIGHT 64
12
+ #define OLED_RESET -1
13
+ #include < Adafruit_GFX.h>
14
+ #include < Adafruit_SSD1306.h>
15
+ Adafruit_SSD1306 display (SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
16
+ #include < Adafruit_NeoPixel.h>
17
+ Adafruit_NeoPixel rgb_led_1 = Adafruit_NeoPixel(1 , 1 , NEO_GRB + NEO_KHZ800);
18
+
19
+
20
+ #endif
21
+ #include " esp_partition.h"
22
+ #include " esp_ota_ops.h"
23
+ #include " esp_system.h"
24
+
25
+ String ssid;
26
+ uint8_t mac[6 ];
27
+
28
+
29
+ // Create an instance of the server
30
+ WebServer server (80 );
31
+ bool displayEnabled;
32
+
33
+ const int BUTTON_PIN = 0 ; // GPIO für den Button
34
+ volatile unsigned long lastPressTime = 0 ; // Zeitpunkt des letzten Drucks
35
+ volatile bool doublePressDetected = false ; // Flag für Doppeldruck
36
+ const unsigned long doublePressInterval = 500 ; // Max. Zeit (in ms) zwischen zwei Drücken für Doppeldruck
37
+ volatile int pressCount = 0 ; // Zählt die Button-Drucke
38
+
39
+ const unsigned char epd_bitmap_wifi [] PROGMEM = {
40
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
41
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x1f , 0x80 , 0x00 , 0x00 , 0x00 , 0x01 ,
42
+ 0xff , 0xf0 , 0x00 , 0x00 , 0x00 , 0x07 , 0xff , 0xfc , 0x00 , 0x00 , 0x00 , 0x1f , 0xe0 , 0xff , 0x00 , 0x00 ,
43
+ 0x00 , 0x3f , 0x00 , 0x0f , 0x80 , 0x00 , 0x00 , 0x7c , 0x00 , 0x03 , 0xe0 , 0x00 , 0x00 , 0xf0 , 0x00 , 0x01 ,
44
+ 0xf0 , 0x00 , 0x01 , 0xe0 , 0x00 , 0x00 , 0x78 , 0x00 , 0x03 , 0xc0 , 0x00 , 0x00 , 0x38 , 0x00 , 0x07 , 0x80 ,
45
+ 0x00 , 0x00 , 0x1c , 0x00 , 0x0f , 0x00 , 0x06 , 0x00 , 0x0e , 0x00 , 0x0e , 0x00 , 0x7f , 0xe0 , 0x0e , 0x00 ,
46
+ 0x0c , 0x01 , 0xff , 0xf0 , 0x06 , 0x00 , 0x00 , 0x07 , 0xff , 0xfc , 0x02 , 0x00 , 0x00 , 0x0f , 0x80 , 0x3e ,
47
+ 0x00 , 0x00 , 0x00 , 0x1f , 0x00 , 0x0f , 0x00 , 0x00 , 0x00 , 0x1c , 0x00 , 0x07 , 0x80 , 0x00 , 0x00 , 0x38 ,
48
+ 0x00 , 0x03 , 0xc0 , 0x00 , 0x00 , 0x70 , 0x00 , 0x01 , 0xc0 , 0x00 , 0x00 , 0x70 , 0x00 , 0x00 , 0xc0 , 0x00 ,
49
+ 0x00 , 0x20 , 0x00 , 0x00 , 0x40 , 0x00 , 0x00 , 0x00 , 0x1f , 0x80 , 0x00 , 0x00 , 0x00 , 0x00 , 0x7f , 0xc0 ,
50
+ 0x00 , 0x00 , 0x00 , 0x00 , 0xff , 0xe0 , 0x00 , 0x00 , 0x00 , 0x01 , 0xe0 , 0xf0 , 0x00 , 0x00 , 0x00 , 0x01 ,
51
+ 0xc0 , 0x78 , 0x00 , 0x00 , 0x00 , 0x03 , 0x80 , 0x38 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x10 , 0x00 , 0x00 ,
52
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
53
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
54
+ 0x06 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x06 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x04 , 0x00 , 0x00 , 0x00 ,
55
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
56
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
57
+ };
58
+
59
+ // 'checkmark', 44x44px
60
+ const unsigned char epd_bitmap_checkmark [] PROGMEM = {
61
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
62
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
63
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
64
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
65
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x01 , 0x80 , 0x00 , 0x00 , 0x00 ,
66
+ 0x00 , 0x03 , 0x80 , 0x00 , 0x00 , 0x00 , 0x00 , 0x07 , 0x80 , 0x00 , 0x00 , 0x00 , 0x00 , 0x0f , 0x00 , 0x00 ,
67
+ 0x00 , 0x00 , 0x00 , 0x1e , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x3c , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x78 ,
68
+ 0x00 , 0x00 , 0x00 , 0x0e , 0x00 , 0xf0 , 0x00 , 0x00 , 0x00 , 0x0f , 0x01 , 0xe0 , 0x00 , 0x00 , 0x00 , 0x0f ,
69
+ 0x83 , 0xc0 , 0x00 , 0x00 , 0x00 , 0x07 , 0xc7 , 0x80 , 0x00 , 0x00 , 0x00 , 0x03 , 0xef , 0x00 , 0x00 , 0x00 ,
70
+ 0x00 , 0x01 , 0xfe , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xfc , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x78 , 0x00 ,
71
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x10 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
72
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
73
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
74
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
75
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
76
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
77
+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
78
+ };
79
+
80
+
81
+ void IRAM_ATTR handleButtonPress () {
82
+ unsigned long currentTime = millis (); // Hole aktuelle Zeit
83
+
84
+ // Vermeidung von Prellen: Wenn der aktuelle Druck zu nahe am letzten liegt, ignoriere ihn
85
+ if (currentTime - lastPressTime > 50 ) {
86
+ pressCount++; // Zähle den Button-Druck
87
+ lastPressTime = currentTime; // Aktualisiere die Zeit des letzten Drückens
88
+
89
+ // Überprüfe, ob dies der zweite Druck innerhalb des Double-Press-Intervalls ist
90
+ if (pressCount == 2 && (currentTime - lastPressTime <= doublePressInterval)) {
91
+ doublePressDetected = true ; // Doppeldruck erkannt
92
+ pressCount = 0 ; // Zähler zurücksetzen
93
+ }
94
+ }
95
+ }
96
+
97
+ // Funktion zum Wechseln der Boot-Partition auf OTA1
98
+ void setBootPartitionToOTA0 () {
99
+ const esp_partition_t * ota0_partition = esp_partition_find_first (
100
+ ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL );
101
+
102
+ if (ota0_partition) {
103
+ // Setze OTA1 als neue Boot-Partition
104
+ esp_ota_set_boot_partition (ota0_partition);
105
+ Serial.println (" Boot partition changed to OTA0. Restarting..." );
106
+
107
+ // Neustart, um von der neuen Partition zu booten
108
+ esp_restart ();
109
+ } else {
110
+ Serial.println (" OTA1 partition not found!" );
111
+ }
112
+ }
113
+
114
+ void setupDisplay () {
115
+ displayEnabled = display.begin (SSD1306_SWITCHCAPVCC, 0x3D );
116
+ if (displayEnabled) {
117
+ display.display ();
118
+ delay (100 );
119
+ display.clearDisplay ();
120
+ }
121
+ }
122
+
123
+ void displayStatusBar (int progress) {
124
+ display.clearDisplay ();
125
+ display.setCursor (24 , 8 );
126
+ display.println (" Sketch wird" );
127
+ display.setCursor (22 , 22 );
128
+ display.println (" hochgeladen!" );
129
+
130
+ display.fillRect (0 , SCREEN_HEIGHT - 24 , SCREEN_WIDTH-4 , 8 , BLACK); // Clear status bar area
131
+ display.drawRect (0 , SCREEN_HEIGHT - 24 , SCREEN_WIDTH-4 , 8 , WHITE); // Draw border
132
+ int filledWidth = (progress * SCREEN_WIDTH-4 ) / 100 ; // Calculate progress width
133
+ display.fillRect (1 , SCREEN_HEIGHT - 23 , filledWidth-4 , 6 , WHITE); // Fill progress bar
134
+
135
+ display.setCursor ((SCREEN_WIDTH/2 )-12 , SCREEN_HEIGHT - 10 );
136
+ display.setTextSize (1 );
137
+ display.setTextColor (WHITE, BLACK);
138
+ display.print (progress);
139
+ display.println (" %" );
140
+ display.display ();
141
+ }
142
+
143
+
144
+ void displayWelcomeScreen () {
145
+ display.clearDisplay ();
146
+
147
+ // Draw WiFi symbol
148
+ display.drawBitmap (0 , 12 , epd_bitmap_wifi, 44 , 44 , WHITE);
149
+
150
+ // Display SSID text
151
+ display.setCursor (40 , 13 );
152
+ display.setTextSize (1 );
153
+ display.setTextColor (WHITE, BLACK);
154
+ display.println (" Verbinde dich" );
155
+ display.setCursor (60 , 27 );
156
+ display.println (" mit:" );
157
+
158
+ // Display SSID
159
+ display.setCursor (40 , 43 );
160
+ display.setTextSize (1 ); // Larger text for SSID
161
+ display.print (ssid);
162
+
163
+ display.display ();
164
+ }
165
+
166
+ void displaySuccessScreen () {
167
+ display.clearDisplay ();
168
+
169
+ // Draw WiFi symbol
170
+ display.drawBitmap (0 , 12 , epd_bitmap_checkmark, 44 , 44 , WHITE);
171
+
172
+ // Display SSID text
173
+ display.setCursor (48 , 22 );
174
+ display.setTextSize (1 );
175
+ display.setTextColor (WHITE, BLACK);
176
+ display.println (" Erfolgreich" );
177
+ display.setCursor (48 , 36 );
178
+ display.println (" hochgeladen!" );
179
+
180
+ display.display ();
181
+ }
182
+
183
+ void wipeDisplay (){
184
+ display.clearDisplay ();
185
+ display.println (" " );
186
+ display.display ();
187
+ }
188
+
189
+
190
+
191
+
192
+ void setupWiFi () {
193
+ WiFi.macAddress (mac);
194
+ char macLastFour[5 ];
195
+ snprintf (macLastFour, sizeof (macLastFour), " %02X%02X" , mac[4 ], mac[5 ]);
196
+ ssid = " senseBox:" + String (macLastFour);
197
+
198
+ // Definiere die IP-Adresse, Gateway und Subnetzmaske
199
+ IPAddress local_IP (192 , 168 , 1 , 1 ); // Die neue IP-Adresse
200
+ IPAddress gateway (192 , 168 , 1 , 1 ); // Gateway-Adresse (kann gleich der IP des APs sein)
201
+ IPAddress subnet (255 , 255 , 255 , 0 ); // Subnetzmaske
202
+
203
+ // Setze die IP-Adresse, Gateway und Subnetzmaske des Access Points
204
+ WiFi.softAPConfig (local_IP, gateway, subnet);
205
+
206
+ // Starte den Access Point
207
+ WiFi.softAP (ssid.c_str ());
208
+ }
209
+
210
+ void setupOTA () {
211
+ // Handle updating process
212
+ server.on (
213
+ " /sketch" , HTTP_POST, []() {
214
+ server.sendHeader (" Connection" , " close" );
215
+ server.send (200 , " text/plain" , (Update.hasError ()) ? " FAIL" : " OK" );
216
+ ESP.restart ();
217
+ },
218
+ []() {
219
+ HTTPUpload& upload = server.upload ();
220
+
221
+ if (upload.status == UPLOAD_FILE_START) {
222
+ Serial.setDebugOutput (true );
223
+ size_t fsize = UPDATE_SIZE_UNKNOWN;
224
+ if (server.clientContentLength () > 0 ){
225
+ fsize = server.clientContentLength ();
226
+ }
227
+ Serial.printf (" Receiving Update: %s, Size: %d\n " , upload.filename .c_str (), fsize);
228
+
229
+ Serial.printf (" Update: %s\n " , upload.filename .c_str ());
230
+ if (!Update.begin (fsize)) { // start with max available size
231
+ Update.printError (Serial);
232
+ }
233
+ } else if (upload.status == UPLOAD_FILE_WRITE) {
234
+ /* flashing firmware to ESP*/
235
+ if (Update.write (upload.buf , upload.currentSize ) != upload.currentSize ) {
236
+ Update.printError (Serial);
237
+ } else {
238
+ int progress = (Update.progress () * 100 ) / Update.size ();
239
+ displayStatusBar (progress); // Update progress on status bar
240
+ }
241
+ } else if (upload.status == UPLOAD_FILE_END) {
242
+ if (Update.end (true )) { // true to set the size to the current progress
243
+ displaySuccessScreen ();
244
+ delay (3000 );
245
+ wipeDisplay ();
246
+ } else {
247
+ Update.printError (Serial);
248
+ }
249
+ Serial.setDebugOutput (false );
250
+ }
251
+ yield ();
252
+ });
253
+ }
254
+
255
+ void setup () {
256
+ // Start Serial communication
257
+ Serial.begin (115200 );
258
+ rgb_led_1.begin ();
259
+ rgb_led_1.setBrightness (30 );
260
+ rgb_led_1.setPixelColor (0 , rgb_led_1.Color (51 , 51 , 255 ));
261
+ rgb_led_1.show ();
262
+
263
+ // Button-Pin als Input konfigurieren
264
+ pinMode (BUTTON_PIN, INPUT_PULLUP);
265
+
266
+ // Interrupt für den Button
267
+ attachInterrupt (digitalPinToInterrupt (BUTTON_PIN), handleButtonPress, FALLING);
268
+
269
+ #ifdef DISPLAY_ENABLED
270
+ setupDisplay ();
271
+ #endif
272
+ setupWiFi ();
273
+ // Set the ESP32 as an access point
274
+ setupOTA ();
275
+ server.begin ();
276
+ }
277
+
278
+ void loop () {
279
+ // Handle client requests
280
+ server.handleClient ();
281
+
282
+ #ifdef DISPLAY_ENABLED
283
+ displayWelcomeScreen ();
284
+ #endif
285
+
286
+ if (doublePressDetected) {
287
+ Serial.println (" Doppeldruck erkannt!" );
288
+ setBootPartitionToOTA0 ();
289
+ #ifdef DISPLAY_ENABLED
290
+ display.setCursor (0 ,0 );
291
+ display.setTextSize (1 );
292
+ display.setTextColor (WHITE,BLACK);
293
+ display.println (" " );
294
+ display.display ();
295
+ delay (50 );
296
+ #endif
297
+ // Neustart, um von der neuen Partition zu booten
298
+ esp_restart ();
299
+ }
300
+ }
0 commit comments